Railway Operation Simulator  v2.15.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 #include <windows.h>
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
251  SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 
1108 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1109 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1110  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1111  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1112  {
1113  Utilities->CallLogPop(2566);
1114  return(1);
1115  }
1116  if(GetRouteGraphicPtr(0,1) == EXG)
1117  {
1118  Utilities->CallLogPop(2567);
1119  return(2);
1120  }
1121  if(GetRouteGraphicPtr(1,0) == EXG)
1122  {
1123  Utilities->CallLogPop(2568);
1124  return(3);
1125  }
1126  if(GetRouteGraphicPtr(1,1) == EXG)
1127  {
1128  Utilities->CallLogPop(2569);
1129  return(3);
1130  }
1131  Utilities->CallLogPop(2570);
1132  return(0);
1133 }
1134 
1135 // ---------------------------------------------------------------------------
1136 // Track functions
1137 // ---------------------------------------------------------------------------
1138 
1139 // ---------------------------------------------------------------------------
1140 
1142 {
1143  TypeOfRoute = 0;
1144  ReducedTimePenalty = false;
1145  BarrierState = Up;
1146  ChangeDuration = 0.0;
1147  BaseElementSpeedTag = 1;
1148  HLoc = 0;
1149  VLoc = 0;
1150  StartTime = TDateTime(0);
1151 }
1152 
1153 // ---------------------------------------------------------------------------
1154 
1156 {
1157 // CurrentSpeedButtonTag = 0; //not assigned yet
1158 
1159  HLocMin = 2000000000;
1160  VLocMin = 2000000000;
1161  HLocMax = -2000000000;
1162  VLocMax = -2000000000;
1163  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1164  CopyFlag = false; // only true for copying, so names aren't copied
1165  AnsiString NL = '\n';
1166 
1167  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1168  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1169  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1170  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1171 
1176 
1177  int InternalLinkCheckArray[9][2] =
1178  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1179 
1180 /* array of valid link values for 'old' location and 'new' location, where
1181  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1182 
1183  for(int x = 0; x < 9; x++)
1184  {
1185  for(int y = 0; y < 2; y++)
1186  {
1187  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1188  }
1189  }
1190 
1191 // Platform and default track element values
1192  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1193 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1194  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1195  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1196  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1197  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1198  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1199  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1200  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1201  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1202 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1203 
1204  int HVArray[10][2] =
1205  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1206 
1207  for(int x = 0; x < 10; x++)
1208  {
1209  for(int y = 0; y < 2; y++)
1210  {
1211  LinkHVArray[x][y] = HVArray[x][y];
1212  }
1213  }
1214  TrackFinished = false;
1215 // DistancesSet = false;
1216 
1217  TSigElement TempSigTable[40] = // original four aspect
1218  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1219  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1220 
1221  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1222  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1223 
1226 
1227  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1228  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1229 
1230  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1231  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1232  {75, 4, RailGraphics->gl75}};
1233 
1234  for(int x = 0; x < 40; x++)
1235  {
1236  SigTable[x] = TempSigTable[x];
1237  }
1238 
1239  TSigElement TempSigTableThreeAspect[40] =
1240  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1241  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1242 
1243  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1244  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1245 
1246  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1247  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1248 
1249  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1250  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1251 
1252  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1253  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1254  {75, 4, RailGraphics->gl75}};
1255 
1256  for(int x = 0; x < 40; x++)
1257  {
1258  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1259  }
1260 
1261  TSigElement TempSigTableTwoAspect[40] =
1262  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1263  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1264 
1265  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1266  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1267 
1268  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1269  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1270 
1271  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1272  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1273 
1274  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1275  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1276  {75, 4, RailGraphics->gl75}};
1277 
1278  for(int x = 0; x < 40; x++)
1279  {
1280  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1281  }
1282 
1283  TSigElement TempSigTableGroundSignal[40] =
1287 
1291 
1295 
1299 
1300  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1303 
1304  for(int x = 0; x < 40; x++)
1305  {
1306  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1307  }
1308 
1309  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1310  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1311  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1312 
1313  for(int x = 0; x < 8; x++)
1314  {
1315  FailedSigTable[x] = TempFailedSigTable[x];
1316  }
1317 
1318  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1319  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1320  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1321 
1322  for(int x = 0; x < 8; x++)
1323  {
1324  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1325  }
1326 
1327 /*
1328  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1329  a single location. These are as follows:-
1330  Directly Adjacent = up, down, left or right - NOT diagonal.
1331  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1332  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1333  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1334 
1335  //t 76
1336  //b 77
1337  //l 78
1338  //r 79
1339  //c 96
1340  //v fb 129
1341  //h fb 130
1342  //v underpass 145
1343  //h underpass 146
1344  //n 131
1345 */
1346 
1347  int Tag76[25][3] =
1348  {{-1, 0, 96}, // c top plat
1349  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1350  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1351  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1352  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1353  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1354  {0, 0, 129}, {0, -1, 145}, // v up
1355  {0, 0, 145}};
1356 
1357  for(int x = 0; x < 25; x++)
1358  {
1359  for(int y = 0; y < 3; y++)
1360  {
1361  Tag76Array[x][y] = Tag76[x][y];
1362  }
1363  }
1364 
1365  int Tag77[25][3] =
1366  {{-1, 0, 96}, // c bot plat
1367  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1368  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1369  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1370  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1371  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1372  {0, 0, 129}, {0, 1, 145}, // v up
1373  {0, 0, 145}};
1374 
1375  for(int x = 0; x < 25; x++)
1376  {
1377  for(int y = 0; y < 3; y++)
1378  {
1379  Tag77Array[x][y] = Tag77[x][y];
1380  }
1381  }
1382 
1383  int Tag78[25][3] =
1384  {{-1, 0, 96}, // c left plat
1385  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1386  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1387  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1388  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1389  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1390  {0, 0, 130}, {-1, 0, 146}, // h up
1391  {0, 0, 146}};
1392 
1393  for(int x = 0; x < 25; x++)
1394  {
1395  for(int y = 0; y < 3; y++)
1396  {
1397  Tag78Array[x][y] = Tag78[x][y];
1398  }
1399  }
1400 
1401  int Tag79[25][3] =
1402  {{-1, 0, 96}, // c right plat
1403  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1404  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1405  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1406  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1407  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1408  {0, 0, 130}, {1, 0, 146}, // h up
1409  {0, 0, 146}};
1410 
1411  for(int x = 0; x < 25; x++)
1412  {
1413  for(int y = 0; y < 3; y++)
1414  {
1415  Tag79Array[x][y] = Tag79[x][y];
1416  }
1417  }
1418 
1419  int Tag96[28][3] =
1420  {{-1, 0, 96}, // c //concourse
1421  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1422  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1423  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1424  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1425  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1426  {0, -1, 129}, {1, 0, 130}, // h fb
1427  {-1, 0, 130}, {0, 1, 145}, // v up
1428  {0, -1, 145}, {1, 0, 146}, // h up
1429  {-1, 0, 146}};
1430 
1431  for(int x = 0; x < 28; x++)
1432  {
1433  for(int y = 0; y < 3; y++)
1434  {
1435  Tag96Array[x][y] = Tag96[x][y];
1436  }
1437  }
1438 
1439  int Tag129[8][3] = // vert fb
1440  {{0, -1, 96}, // c
1441  {0, -1, 77}, // b
1442  {0, -1, 129}, // v fb
1443 
1444  {0, 1, 96}, // c
1445  {0, 1, 76}, // t
1446  {0, 1, 129}, // v fb
1447 
1448  {0, 0, 76}, // t
1449  {0, 0, 77}}; // b
1450 
1451  for(int x = 0; x < 8; x++)
1452  {
1453  for(int y = 0; y < 3; y++)
1454  {
1455  Tag129Array[x][y] = Tag129[x][y];
1456  }
1457  }
1458 
1459  int Tag145[8][3] = // vert up
1460  {{0, -1, 96}, // c
1461  {0, -1, 77}, // b
1462  {0, -1, 145}, // v fb
1463 
1464  {0, 1, 96}, // c
1465  {0, 1, 76}, // t
1466  {0, 1, 145}, // v fb
1467 
1468  {0, 0, 76}, // t
1469  {0, 0, 77}}; // b
1470 
1471  for(int x = 0; x < 8; x++)
1472  {
1473  for(int y = 0; y < 3; y++)
1474  {
1475  Tag145Array[x][y] = Tag145[x][y];
1476  }
1477  }
1478 
1479  int Tag130[8][3] = // hor fb
1480  {{-1, 0, 96}, // c
1481  {-1, 0, 79}, // r
1482  {-1, 0, 130}, // h fb
1483 
1484  {1, 0, 96}, // c
1485  {1, 0, 78}, // l
1486  {1, 0, 130}, // h fb
1487 
1488  {0, 0, 78}, // l
1489  {0, 0, 79}}; // r
1490 
1491  for(int x = 0; x < 8; x++)
1492  {
1493  for(int y = 0; y < 3; y++)
1494  {
1495  Tag130Array[x][y] = Tag130[x][y];
1496  }
1497  }
1498 
1499  int Tag146[8][3] = // hor up
1500  {{-1, 0, 96}, // c
1501  {-1, 0, 79}, // r
1502  {-1, 0, 146}, // h fb
1503 
1504  {1, 0, 96}, // c
1505  {1, 0, 78}, // l
1506  {1, 0, 146}, // h fb
1507 
1508  {0, 0, 78}, // l
1509  {0, 0, 79}}; // r
1510 
1511  for(int x = 0; x < 8; x++)
1512  {
1513  for(int y = 0; y < 3; y++)
1514  {
1515  Tag146Array[x][y] = Tag146[x][y];
1516  }
1517  }
1518 
1519  int Tag131[4][3] =
1520  {{-1, 0, 131}, // n
1521  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1522 
1523  for(int x = 0; x < 4; x++)
1524  {
1525  for(int y = 0; y < 3; y++)
1526  {
1527  Tag131Array[x][y] = Tag131[x][y];
1528  }
1529  }
1530 
1531  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1532  {
1533  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1534  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1535  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1536  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1537  140, 144, 145, 146
1538  };
1539 
1540  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1541  {
1542  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1543  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1544  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1545  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1546  141, 144, 145, 146
1547  };
1548 
1549  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1550  {
1551  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1552  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1553  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1554  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1555  141, 144, 146, 145
1556  };
1557 
1558  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1559  {
1560  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1561  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1562  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1563  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1564  140, 144, 146, 145
1565  };
1566 
1567  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1568  {
1569  FlipArray[x] = InternalFlipArray[x];
1570  MirrorArray[x] = InternalMirrorArray[x];
1571  RotRightArray[x] = InternalRotRightArray[x];
1572  RotLeftArray[x] = InternalRotLeftArray[x];
1573  }
1574 }
1575 
1576 // ---------------------------------------------------------------------------
1578 {
1579 // delete TrackVectorPtr;
1580 // delete FixedTrackArrayPtr;
1581  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1582 
1583  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1584  {
1585  delete UGMIt->second;
1586  UGMIt++;
1587  }
1588  delete GapFlashGreen;
1589  delete GapFlashRed;
1590  // all the rest are cleared by the relevant automatic destructors
1591 }
1592 
1593 // ---------------------------------------------------------------------------
1594 
1596 {
1597  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1598  {
1599 // loc 0 not used, set to bmSolidBgnd
1603 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1623  };
1624 
1625  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1626  {
1627 // loc 0 not used, set to smSolidBgnd
1631 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1650  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1651  };
1652 
1653 // track types
1654  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1655  {
1656  Erase, // 1 0
1657  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1658  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1659  Crossover, Crossover, // 2 15-16
1660  Unused, // 17 (was for text in earlier development) //1 17
1663  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1667  Platform, Platform, Platform, Platform, // 4 76-79
1670  Concourse, // 1 96
1673  Simple, Simple, Simple, Simple, // 4 125-128
1674  FootCrossing, FootCrossing, // 2 129-130
1675  NamedNonStationLocation, // 1 131
1676  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1677  Simple, Simple, Simple, Simple, // 4 140-143
1678  LevelCrossing, // 1 144
1679  FootCrossing, FootCrossing // 2 145 & 146
1680  };
1681 
1682 // links
1683  int Links[FirstUnusedSpeedTagNumber][4] =
1684  {{-1, -1, -1, -1}, // erase element
1685  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1686  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1687 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1688  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1689  {-1, -1, -1, -1}, // unused
1690  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1691  {2, 7, -1, -1}, // simple
1692  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1693 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1694 // (or right diverging if no straight)
1695  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1696  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1697  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1698  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1699  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1700  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1701  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1702  {-1, -1, -1, -1}, // Concourse
1703  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1704  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1705  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1707  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1708  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1709  {-1, -1, -1, -1}, // NamedNonStationLocation
1710  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1711 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1712  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1713  {-1, -1, -1, -1}, // level crossing
1714  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1715  };
1716 
1718  {{NotSet, NotSet, NotSet, NotSet}, // unused
1722  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1724  {NotSet, NotSet, NotSet, NotSet}, // unused
1728  {Connection, Connection, NotSet, NotSet}, // simple
1732  {Lead, Trail, Lead, Trail}, // points
1734  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1742  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1748  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1757  {Connection, Connection, NotSet, NotSet}, // Arrows
1759  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1761  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1763  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1764  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1765  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1766  };
1767 
1768  for(int x = 0; x < 17; x++)
1769  {
1770  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1771  }
1772  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1773 // 17 was the old text value so don't want any graphics (now disused)
1774  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1775  {
1776  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1777  }
1778 }
1779 
1780 // ---------------------------------------------------------------------------
1781 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1782  ExistingGraphicLoaded(false), Width(16), Height(16)
1783 {
1784  OriginalGraphic = new Graphics::TBitmap;
1785  OriginalGraphic->PixelFormat = pf8bit;
1786  OriginalGraphic->Width = Width;
1787  OriginalGraphic->Height = Height;
1788  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1789 }
1790 
1791 // ---------------------------------------------------------------------------
1792 
1793 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1794  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1795 {
1796  OriginalGraphic = new Graphics::TBitmap;
1797  OriginalGraphic->PixelFormat = pf8bit;
1798  OriginalGraphic->Width = Width;
1799  OriginalGraphic->Height = Height;
1800  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1801 }
1802 
1803 // ---------------------------------------------------------------------------
1804 
1806 {
1807  delete OriginalGraphic;
1808 }
1809 
1810 // ---------------------------------------------------------------------------
1811 
1812 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1813 {
1814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1815  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1816  VPos = VPosIn;
1817  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1818 
1819  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1820  SourceRect.init(Left, Top, Left + Width, Top + Height);
1821  ScreenSourceSet = true;
1822  Utilities->CallLogPop(422);
1823 }
1824 
1825 // ---------------------------------------------------------------------------
1826 
1828 {
1829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1830  if(!OverlayLoaded)
1831  {
1832  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1833  }
1834  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1835  {
1836  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1837  }
1838  if(!ScreenSourceSet)
1839  {
1840  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1841  }
1842  if(ExistingGraphicLoaded) // can only call one of the load functions
1843  {
1844  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1845  }
1846  if(OverlayPlotted) // don't load from screen if overlay plotted
1847  {
1848  Utilities->CallLogPop(775);
1849  return;
1850  }
1851  TRect DestRect(0, 0, Width, Height);
1852 
1854  OriginalLoaded = true;
1855  ScreenGraphicLoaded = true;
1856  Utilities->CallLogPop(423);
1857 }
1858 
1859 // ---------------------------------------------------------------------------
1860 
1861 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1862 /*
1863  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1864 */
1865 {
1866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1867  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1868  if(!OverlayLoaded)
1869  {
1870  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1871  }
1872  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1873  {
1874  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1875  }
1876  if(ScreenGraphicLoaded) // can only call one of the load functions
1877  {
1878  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1879  }
1880  Width = WidthIn;
1881  Height = HeightIn;
1882  OriginalGraphic->Width = Width;
1883  OriginalGraphic->Height = Height;
1884  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1885  VPos += VOffset;
1886  TRect DestRect(0, 0, Width, Height);
1887 
1888  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1889  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1890  OriginalLoaded = true;
1891  ExistingGraphicLoaded = true;
1892  Utilities->CallLogPop(424);
1893 }
1894 
1895 // ---------------------------------------------------------------------------
1896 
1897 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1898 {
1899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1900  OverlayGraphic = Overlay;
1901  OverlayLoaded = true;
1902  Utilities->CallLogPop(425);
1903 }
1904 
1905 // ---------------------------------------------------------------------------
1906 
1908 {
1909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1910  if(!OverlayLoaded)
1911  {
1912  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1913  }
1914  if(!OverlayPlotted)
1915  {
1916  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1917  Disp->Update();
1918  OverlayPlotted = true;
1919  }
1920  Utilities->CallLogPop(426);
1921 }
1922 
1923 // ---------------------------------------------------------------------------
1924 
1926 {
1927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1928  if(OverlayPlotted)
1929  {
1930  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1931  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1932  {
1933  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1934  }
1935  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1936  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1937  OverlayPlotted = false;
1938  }
1939  Utilities->CallLogPop(427);
1940 }
1941 
1942 // ---------------------------------------------------------------------------
1943 
1945 {
1946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1947  bool TrackPresent = false;
1948 
1949  if(InactiveTrackVector.size() != 0)
1950  {
1951  Utilities->CallLogPop(1333);
1952  return(false);
1953  }
1954  else if(TrackVector.size() == 0)
1955  {
1956  Utilities->CallLogPop(1334);
1957  return(true);
1958  }
1959  else
1960  {
1961  for(unsigned int x = 0; x < TrackVector.size(); x++)
1962  {
1963  if((TrackElementAt(1042, x).SpeedTag != 0))
1964  {
1965  TrackPresent = true;
1966  }
1967  }
1968  }
1969  Utilities->CallLogPop(1335);
1970  return(!TrackPresent);
1971 }
1972 
1973 // ---------------------------------------------------------------------------
1974 
1975 bool TTrack::NoActiveTrack(int Caller)
1976 {
1977  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1978  bool TrackPresent = false;
1979 
1980  if(TrackVector.size() == 0)
1981  {
1982  Utilities->CallLogPop(1582);
1983  return(true);
1984  }
1985  else
1986  {
1987  for(unsigned int x = 0; x < TrackVector.size(); x++)
1988  {
1989  if((TrackElementAt(1043, x).SpeedTag != 0))
1990  {
1991  TrackPresent = true;
1992  }
1993  break;
1994  }
1995  }
1996  Utilities->CallLogPop(1583);
1997  return(!TrackPresent);
1998 }
1999 
2000 // ---------------------------------------------------------------------------
2001 
2002 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2003 {
2004  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2005  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2006  TrackEraseSuccessfulFlag = false;
2007 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2008 // since have to match platforms as well as track
2009 // used to set TrackFinished to false if an element erased
2010 
2011  ErasedTrackVectorPosition = -1; // marker for no element erased
2012  AnsiString SName = "", ErrorString;
2014  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2015  TTrackMapIterator TrackMapPtr;
2016  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2017 
2018  if(TrackVector.size() != 0)
2019  {
2020  TrackMapKeyPair.first = HLocInput;
2021  TrackMapKeyPair.second = VLocInput;
2022  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2023  if(TrackMapPtr != TrackMap.end())
2024  {
2025  bool FoundFlag;
2026  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2027  if(FoundFlag) // should find it as it's in the map
2028  {
2029  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2030  {
2031  SName = TrackElementAt(1, VecPos).LocationName;
2032  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2033  if(ErrorString != "")
2034  {
2035  throw Exception(ErrorString + " for EraseTrackElement 1");
2036  }
2037  LocationNameMultiMap.erase(SNIt);
2038  }
2039  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2040  // ensure erase vector element before map element as iterator no longer valid after a map erase
2041  TrackMap.erase(TrackMapPtr);
2042  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2043  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2045  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2046  if(SName != "")
2047  {
2048  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2049  int HPos, VPos;
2050  if(TextHandler->FindText(1, SName, HPos, VPos))
2051  {
2052  if(TextHandler->TextErase(5, HPos, VPos, SName))
2053  {
2054  ;
2055  } // condition not used
2056 
2057  }
2058  }
2059  ErasedTrackVectorPosition = VecPos;
2060  TrackEraseSuccessfulFlag = true;
2061  }
2062  }
2063  }
2064  if(InactiveTrackVector.size() != 0)
2065  {
2066  unsigned int VecPos;
2067  InactiveTrackMapKeyPair.first = HLocInput;
2068  InactiveTrackMapKeyPair.second = VLocInput;
2069  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2070  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2071  {
2072  SName = "";
2073  VecPos = InactiveTrack2MultiMapIterator->second;
2074  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2075  {
2076  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2077  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2078  if(ErrorString != "")
2079  {
2080  throw Exception(ErrorString + " for EraseTrackElement 2A");
2081  }
2082  LocationNameMultiMap.erase(SNIt);
2083  }
2084  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2085  // ensure erase vector element before map element as iterator no longer valid after a map erase
2086  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2087  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2088  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2090  TrackEraseSuccessfulFlag = true;
2091  if(SName != "")
2092  {
2093  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2094  int HPos, VPos;
2095  if(TextHandler->FindText(2, SName, HPos, VPos))
2096  {
2097  if(TextHandler->TextErase(6, HPos, VPos, SName))
2098  {
2099  ;
2100  } // condition not used
2101 
2102  }
2103  }
2104  }
2105  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2106  {
2107  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2108  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2109  {
2110  SName = "";
2111  VecPos = InactiveTrack2MultiMapIterator->second;
2112  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2113  {
2114  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2115  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2116  if(ErrorString != "")
2117  {
2118  throw Exception(ErrorString + " for EraseTrackElement 2B");
2119  }
2120  LocationNameMultiMap.erase(SNIt);
2121  }
2122  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2123  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2124  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2126  if(SName != "")
2127  {
2128  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2129  int HPos, VPos;
2130  if(TextHandler->FindText(3, SName, HPos, VPos))
2131  {
2132  if(TextHandler->TextErase(7, HPos, VPos, SName))
2133  {
2134  ;
2135  } // condition not used
2136 
2137  }
2138  }
2139  }
2140  }
2141  }
2142  if(TrackEraseSuccessfulFlag)
2143  {
2144  CalcHLocMinEtc(2);
2145  SetTrackFinished(false);
2146  }
2147  if(InternalChecks)
2148  {
2149  CheckMapAndTrack(1); // test
2150  CheckMapAndInactiveTrack(1); // test
2151  CheckLocationNameMultiMap(6); // test
2152  }
2153  Utilities->CallLogPop(428);
2154 }
2155 
2156 // ---------------------------------------------------------------------------
2157 
2158 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2159 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2160 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2161 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2162 {
2163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2164  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2165  bool PlatAllowedFlag = false;
2166 
2167  TrackLinkingRequiredFlag = false;
2168 /*
2169  Not erase, that covered separately.
2170  First check if Current SpeedButton assigned, then check if a platform and only
2171  permit if an appropriate trackpiece already there & not a same platform there.
2172  - can't enter a platform without track first.
2173  Then for non-platforms, check if a track piece already present at location &
2174  reject if so.
2175 */
2176 
2177  TLocationNameMultiMapEntry LocationNameEntry;
2178 
2179  LocationNameEntry.first = "";
2180  if(CurrentTag == 0)
2181  {
2182  Utilities->CallLogPop(429);
2183  return; // not assigned yet
2184  }
2185  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2186 
2187  TempTrackElement.HLoc = HLocInput;
2188  TempTrackElement.VLoc = VLocInput;
2189  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2190 // new at version 0.6 - set signal aspect depending on build mode
2191 
2192  if(TempTrackElement.TrackType == SignalPost)
2193  {
2194  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2195  // pasting a SignalPost can only have values 1 to 4
2196  {
2198  {
2199  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2200  }
2202  {
2203  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2204  }
2206  {
2207  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2208  }
2209  else
2210  {
2211  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2212  }
2213  }
2214  else if(Aspect == 1)
2215  {
2216  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2217  }
2218  else if(Aspect == 2)
2219  {
2220  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2221  }
2222  else if(Aspect == 3)
2223  {
2224  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2225  }
2226  else
2227  {
2228  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2229  }
2230  }
2231  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2232  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2233  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2234  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2235 
2236  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2237  {
2239  {
2240  NonStationOrLevelCrossingPresent = true;
2241  }
2242  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2243  {
2244  NonStationOrLevelCrossingPresent = true;
2245  }
2246  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2247  {
2248  PlatformPresent = true;
2249  }
2250  // no need to check IMPair.second since if that exists it is because .first is a platform
2251  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2252  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2253  }
2254 // check platforms
2255  if(TempTrackElement.TrackType == Platform)
2256  {
2257  if(FoundFlag) // active track element already there
2258  {
2259  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2260  {
2261  ;
2262  }
2263  // same platform type already there so above keeps PlatAllowedFlag false
2264  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2265  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2266  {
2267  PlatAllowedFlag = true;
2268  }
2269  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2270  {
2271  PlatAllowedFlag = true;
2272  }
2273  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2274  {
2275  PlatAllowedFlag = true;
2276  }
2277  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2278  {
2279  PlatAllowedFlag = true;
2280  }
2281  if(PlatAllowedFlag)
2282  {
2283  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2284  TrackPush(1, TempTrackElement);
2285  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2286  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2287  // Must be called AFTER TrackPush
2288  // No need to plot the element - Clearand ... called after this function called
2289  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2290  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2291 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2292 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2293 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2294  if(InternalChecks)
2295  {
2296  CheckMapAndInactiveTrack(5); // test
2297  CheckLocationNameMultiMap(4); // test
2298  }
2299  Utilities->CallLogPop(430);
2300  return;
2301  }
2302  } // if(FoundFlag)
2303 
2304  Utilities->CallLogPop(431);
2305  return;
2306  } // if platform
2307 
2308 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2309  if(TempTrackElement.TrackType == NamedNonStationLocation)
2310  {
2311  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2312  (!FoundFlag && !InactiveFoundFlag))
2313  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2314  {
2315  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2316  TrackPush(2, TempTrackElement);
2317  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2318  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2319  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2320  {
2321 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2322 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2323 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2324  }
2325  if(InternalChecks)
2326  {
2327  CheckMapAndInactiveTrack(11); // test
2328  CheckLocationNameMultiMap(12); // test
2329  }
2330  Utilities->CallLogPop(432);
2331  return;
2332  }
2333  else
2334  {
2335  Utilities->CallLogPop(433);
2336  return;
2337  }
2338  }
2339 // check if a level crossing - OK if placed on a plain straight track
2340  if(TempTrackElement.TrackType == LevelCrossing)
2341  {
2342  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2343  {
2344  TrackPush(11, TempTrackElement);
2345  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2346 // no need for reference to LC element as can't be open
2347  TrackLinkingRequiredFlag = true;
2348  Utilities->CallLogPop(1907);
2349  return;
2350  }
2351  else
2352  {
2353  Utilities->CallLogPop(1906);
2354  return; // was a level crossing but can't place it for some reason
2355  }
2356  }
2357 
2358 // check if another element already there
2359  else if(FoundFlag || InactiveFoundFlag)
2360  {
2361  Utilities->CallLogPop(434);
2362  return; // something already there (active or inactive track)
2363  }
2364 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2365 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2366 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2367 // do this after pushed into vector so that can use EnterLocationName
2368 
2369  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2370  {
2371  TrackPush(3, TempTrackElement);
2372  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2373  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2374  }
2375  else if(TempTrackElement.TrackType == Points)
2376  {
2377  TrackPush(4, TempTrackElement);
2378  bool BothPointFillets = true;
2379  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2380  }
2381  else if(TempTrackElement.TrackType == SignalPost)
2382  {
2383  TrackPush(10, TempTrackElement);
2384  PlotSignal(12, TempTrackElement, Display);
2385  }
2386  else
2387  {
2388  TrackPush(5, TempTrackElement);
2389  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2390  }
2391  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2392  {
2393  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2394  }
2395  if(InternalChecks)
2396  {
2397  CheckMapAndTrack(2); // test
2398  CheckMapAndInactiveTrack(2); // test
2399  CheckLocationNameMultiMap(5); // test
2400  }
2401  Utilities->CallLogPop(2062);
2402 }
2403 
2404 // ---------------------------------------------------------------------------
2405 
2406 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2407  bool InternalChecks)
2408 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2409 {
2410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2411  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2412  bool PlatAllowedFlag = false;
2413 
2414  TrackLinkingRequiredFlag = false;
2415  TLocationNameMultiMapEntry LocationNameEntry;
2416 
2417  LocationNameEntry.first = "";
2418  if(TempTrackElement.SpeedTag == 0)
2419  {
2420  Utilities->CallLogPop(2063);
2421  return; // not assigned yet
2422  }
2423  TempTrackElement.HLoc = HLocInput;
2424  TempTrackElement.VLoc = VLocInput;
2425  for(int x = 0; x < 4; x++) // unset any gaps
2426  {
2427  if(TempTrackElement.Config[x] == Gap)
2428  {
2429  TempTrackElement.ConnLinkPos[x] = -1;
2430  }
2431  TempTrackElement.Conn[x] = -1;
2432  }
2433  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2434 // new at version 0.6 - set signal aspect depending on build mode
2435  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2436  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2437 
2438  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2439  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2440  // for the active track element because these aren't set
2441  // if don't do this then get a mismatch error during map checks later
2442 
2443  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2444 
2445  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2446  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2447 
2448  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2449  {
2450  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2451  {
2452  NonStationOrLevelCrossingPresent = true;
2453  }
2454  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2455  {
2456  NonStationOrLevelCrossingPresent = true;
2457  }
2458  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2459  {
2460  PlatformPresent = true;
2461  }
2462  // no need to check IMPair.second since if that exists it is because .first is a platform
2463  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2464  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2465  }
2466 // check platforms
2467  if(TempTrackElement.TrackType == Platform)
2468  {
2469  if(FoundFlag) // active track element already there
2470  {
2471  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2472  {
2473  ;
2474  }
2475  // same platform type already there so above keeps PlatAllowedFlag false
2476  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2477  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2478  {
2479  PlatAllowedFlag = true;
2480  }
2481  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2482  {
2483  PlatAllowedFlag = true;
2484  }
2485  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2486  {
2487  PlatAllowedFlag = true;
2488  }
2489  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2490  {
2491  PlatAllowedFlag = true;
2492  }
2493  if(PlatAllowedFlag)
2494  {
2495  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2496  TrackPush(12, TempTrackElement);
2497 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2498  {
2499  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2500  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2501  }
2502  // Must be called AFTER TrackPush
2503 // No need to plot the element - Clearand ... called after this function called
2504  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2505  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2506 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2507 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2508 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2509  if(InternalChecks)
2510  {
2511  CheckMapAndInactiveTrack(12); // test
2512  CheckLocationNameMultiMap(20); // test
2513  }
2514  Utilities->CallLogPop(2064);
2515  return;
2516  }
2517  } // if(FoundFlag)
2518 
2519  Utilities->CallLogPop(2065);
2520  return;
2521  } // if platform
2522 
2523 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2524  if(TempTrackElement.TrackType == NamedNonStationLocation)
2525  {
2526  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2527  (!FoundFlag && !InactiveFoundFlag))
2528  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2529  {
2530  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2531  TrackPush(13, TempTrackElement);
2532 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2533  {
2534  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2535  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2536  }
2537  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2538  {
2539 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2540 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2541 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2542  }
2543  if(InternalChecks)
2544  {
2545  CheckMapAndInactiveTrack(13); // test
2546  CheckLocationNameMultiMap(21); // test
2547  }
2548  Utilities->CallLogPop(2066);
2549  return;
2550  }
2551  else
2552  {
2553  Utilities->CallLogPop(2067);
2554  return;
2555  }
2556  }
2557 // check if a level crossing - OK if placed on a plain straight track
2558  if(TempTrackElement.TrackType == LevelCrossing)
2559  {
2560  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2561  {
2562  TrackPush(14, TempTrackElement);
2563  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2564 // no need for reference to LC element as can't be open
2565  TrackLinkingRequiredFlag = true;
2566  Utilities->CallLogPop(2068);
2567  return;
2568  }
2569  else
2570  {
2571  Utilities->CallLogPop(2069);
2572  return; // was a level crossing but can't place it for some reason
2573  }
2574  }
2575 
2576 // check if another element already there
2577  else if(FoundFlag || InactiveFoundFlag)
2578  {
2579  Utilities->CallLogPop(2070);
2580  return; // something already there (active or inactive track)
2581  }
2582 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2583 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2584 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2585 // do this after pushed into vector so that can use EnterLocationName
2586 
2587  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2588  {
2589  TrackPush(15, TempTrackElement);
2590  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2591  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2592  }
2593  else if(TempTrackElement.TrackType == Points)
2594  {
2595  TrackPush(16, TempTrackElement);
2596  bool BothPointFillets = true;
2597  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2598  }
2599  else if(TempTrackElement.TrackType == SignalPost)
2600  {
2601  TrackPush(17, TempTrackElement);
2602  PlotSignal(14, TempTrackElement, Display);
2603  }
2604  else
2605  {
2606  TrackPush(18, TempTrackElement);
2607  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2608  }
2609  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2610  {
2611  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2612  }
2613  if(InternalChecks)
2614  {
2615  CheckMapAndTrack(12); // test
2616  CheckMapAndInactiveTrack(14); // test
2617  CheckLocationNameMultiMap(22); // test
2618  }
2619  Utilities->CallLogPop(2071);
2620 }
2621 
2622 // ---------------------------------------------------------------------------
2623 
2624 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2625 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2626 // return bool = true for success
2627 // LocError = true for location error & HLoc & VLoc to be inverted
2628 {
2629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2630  LocError = false;
2631  SetTrackFinished(false);
2632  if(TrackVector.size() == 0)
2633  {
2634  Utilities->CallLogPop(437);
2635  return(false);
2636  }
2637  if(GapsUnset(7))
2638  {
2639  if(GiveMessages)
2640  {
2641  ShowMessage("Gaps must be set before track can be validated");
2642  }
2643  Utilities->CallLogPop(1135);
2644  return(false);
2645  }
2646 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2647 // returns true for any unset gaps
2649  {
2650  // can keep this exception as protected by the GapsUnset call above
2651  throw Exception("Error, gaps unset when TryToConnectTrack called");
2652  }
2654  CheckGapMap(1); // test
2655 // Gap connections now securely defined
2656 
2657  CheckMapAndTrack(8); // test
2658 
2659 // Perform a pre-check prior to TrackMap being compiled
2660  if(GiveMessages)
2661  {
2662  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2663  {
2664  Utilities->CallLogPop(439);
2665  return(false);
2666  }
2667  }
2668  else
2669  {
2670  if(!LinkTrackNoMessages(1, false))
2671  {
2672  Utilities->CallLogPop(1131);
2673  return(false);
2674  }
2675  }
2676 // here if pre-check successful
2677  if(!RepositionAndMapTrack(0))
2678  {
2679  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2680  Utilities->CallLogPop(1138);
2681  return(false);
2682  }
2683 // now perform the final assembly - FinalCall = true
2684  if(GiveMessages)
2685  {
2686  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2687  {
2688  Utilities->CallLogPop(1116);
2689  return(false);
2690  }
2691  }
2692  else
2693  {
2694  if(!LinkTrackNoMessages(2, true))
2695  {
2696  Utilities->CallLogPop(1132);
2697  return(false);
2698  }
2699  }
2700 // success
2701 
2702  PopulateLCVector(0);
2703  CheckGapMap(2); // test
2704  CheckMapAndTrack(3); // test
2705  CheckMapAndInactiveTrack(3); // test
2706  CheckLocationNameMultiMap(9); // test
2707  SetTrackFinished(true);
2708 
2709 // Build ContinuationNameMap
2710  std::pair<AnsiString, char>TempMapPair;
2711 
2712  ContinuationNameMap.clear();
2713  for(int x = 0; x < Track->TrackVectorSize(); x++)
2714  {
2715  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2716  {
2717  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2718  TempMapPair.second = 'x'; // unused
2719  ContinuationNameMap.insert(TempMapPair);
2720  }
2721  }
2722 
2723 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2724 //(don't report blue areas without track as these unlikely to be mistakes)
2725 
2726  if(TrackFinished)
2727  {
2728  AnsiString Name = "";
2729  typedef std::list<AnsiString> TNoPlatsList;
2730  TNoPlatsList::iterator NPLIt;
2731  TNoPlatsList NoPlatsList;
2732  typedef std::list<AnsiString> TLocNameList;
2733  TLocNameList LocNameList; //single entry for each name
2736  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2737  {
2738  LocNameList.push_back(LNMMIt->first);
2739  }
2740  LocNameList.sort();
2741  LocNameList.unique();
2742  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2743  {
2744  Name = *LNLIt;
2745  MMRange = LocationNameMultiMap.equal_range(Name);
2746  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2747  {
2748  continue;
2749  }
2750  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2751  {
2752  if((LNMMIt->second) < 0) //active track element
2753  {
2754  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2755  {
2756  break;
2757  }
2758  }
2759  else //inactive
2760  {
2761  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2762  {
2763  break;
2764  }
2765  }
2766  TempIt = MMRange.second;
2767  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2768  {
2769  NoPlatsList.push_back(Name);
2770  }
2771  }
2772  }
2773  if(!NoPlatsList.empty())
2774  {
2775  AnsiString NoPlatsAnsiList = "";
2776  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2777  {
2778  NoPlatsAnsiList += *NPLIt + '\n';
2779  }
2780  if(!NoPlatsMessageSent)
2781  {
2782  if(NoPlatsList.size() > 1)
2783  {
2784  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2785  }
2786  else
2787  {
2788  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2789  }
2790  NoPlatsMessageSent = true;
2791  }
2792  }
2793  }
2794  Utilities->CallLogPop(440);
2795  return(true);
2796 }
2797 
2798 // ---------------------------------------------------------------------------
2799 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2800 // unused - too time-consuming - double brute force search
2801 {
2802  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2803  int NewHLoc, NewVLoc;
2804  bool ConnectionFoundFlag, LinkFoundFlag;
2805 
2806  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2807  {
2808  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2809  {
2810  if(TrackElementAt(1061, x).Link[y] <= 0)
2811  {
2812  continue; // no link
2813  }
2814  if(TrackElementAt(1062, x).Config[y] == End)
2815  {
2816  continue; // buffer or continuation
2817  }
2818  if(TrackElementAt(1063, x).Config[y] == Gap)
2819  {
2820  continue; // gap jump
2821  }
2822  // get required H & V for track element joining link 'y'
2823  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2824  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2825  // find track element if present
2826  ConnectionFoundFlag = false;
2827  for(unsigned int z = 0; z < TrackVector.size(); z++)
2828  {
2829 // if(TrackElementAt(5, z).TrackType == Platform)
2830 // continue; //skip platforms
2831  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2832  {
2833  ConnectionFoundFlag = true;
2834  // find connecting link in the newly found track element if there is one
2835  LinkFoundFlag = false;
2836  for(unsigned int a = 0; a < 4; a++)
2837  {
2838  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2839  {
2840  LinkFoundFlag = true;
2841  }
2842  }
2843  // if there isn't a corresponding link set the invert values for the offending element
2844  if(!LinkFoundFlag)
2845  {
2846  HLoc = TrackElementAt(1072, x).HLoc;
2847  VLoc = TrackElementAt(1073, x).VLoc;
2848  Utilities->CallLogPop(441);
2849  return(true);
2850  }
2851  break; // success, so break out of 'z' loop
2852  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2853 
2854  } // for z...
2855  // if there isn't a connection set the invert values for the offending element
2856  if(!ConnectionFoundFlag)
2857  {
2858  HLoc = TrackElementAt(1074, x).HLoc;
2859  VLoc = TrackElementAt(1075, x).VLoc;
2860  Utilities->CallLogPop(442);
2861  return(true);
2862  }
2863  } // for y....
2864  } // for x...
2865  Utilities->CallLogPop(443);
2866  return(false); // all OK
2867 }
2868 
2869 // ---------------------------------------------------------------------------
2870 
2871 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2872 {
2873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2874  TrackElement.LogTrack(0));
2875  bool FoundFlag;
2876 
2877  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2878  if(FoundFlag)
2879  {
2880  TrackElement = TrackElementAt(1076, Position);
2881  }
2882  Utilities->CallLogPop(444);
2883  return(FoundFlag);
2884 }
2885 
2886 // ---------------------------------------------------------------------------
2887 
2889 {
2890  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2891  if(NextTrackElementPtr >= TrackVector.end())
2892  {
2893  Utilities->CallLogPop(1336);
2894  return(false);
2895  }
2896  Next = *NextTrackElementPtr;
2898  Utilities->CallLogPop(1337);
2899  return(true);
2900 }
2901 
2902 // ---------------------------------------------------------------------------
2903 
2905 {
2906  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2908  {
2909  Utilities->CallLogPop(1338);
2910  return(false);
2911  }
2912  Next = *NextTrackElementPtr;
2914  Utilities->CallLogPop(1339);
2915  return(true);
2916 }
2917 
2918 // ---------------------------------------------------------------------------
2919 
2920 int TTrack::NumberOfGaps(int Caller)
2921 
2922 {
2923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2924  int Count = 0;
2925 
2926  if(TrackVector.size() == 0)
2927  {
2928  Utilities->CallLogPop(1340);
2929  return(0);
2930  }
2931  for(unsigned int x = 0; x < TrackVector.size(); x++)
2932  {
2933  if(TrackElementAt(1077, x).TrackType == GapJump)
2934  {
2935  Count++;
2936  }
2937  }
2938  Utilities->CallLogPop(1341);
2939  return(Count);
2940 }
2941 
2942 // ---------------------------------------------------------------------------
2944 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2945 // returns true for any unset gaps
2946 {
2947  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2948  bool UnsetGaps = false;
2949 
2950  if(TrackVector.size() == 0)
2951  {
2952  Utilities->CallLogPop(445);
2953  return(false);
2954  }
2955  for(unsigned int x = 0; x < TrackVector.size(); x++)
2956  {
2957  if(TrackElementAt(1078, x).TrackType != GapJump)
2958  {
2959  for(unsigned int y = 0; y < 4; y++)
2960  {
2961  TrackElementAt(1079, x).Conn[y] = -1;
2962  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2963  }
2964  }
2965  else // GapJump
2966  {
2967 // int tempint = TrackElementAt(, x).Conn[0);
2968 
2969  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2970  {
2971  for(unsigned int y = 0; y < 4; y++)
2972  {
2973  TrackElementAt(1082, x).Conn[y] = -1;
2974  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2975  }
2976  UnsetGaps = true;
2977  continue; // to next 'x'
2978  }
2979  else // set, but may not have matching element, or that element may not be set
2980  {
2981  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2982  {
2983  TrackElementAt(1084, x).Conn[y] = -1;
2984  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2985  }
2986 
2987  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2988  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2989  {
2990  for(unsigned int y = 0; y < 4; y++)
2991  {
2992  TrackElementAt(1087, x).Conn[y] = -1;
2993  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2994  }
2995  UnsetGaps = true;
2996  continue; // to next 'x'
2997  }
2998 // here if gap connection is itself a GapJump
2999  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3000  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3001  // if not clear Conns & CLks & reset Lk[0]
3002  {
3003  for(unsigned int y = 0; y < 4; y++)
3004  {
3005  TrackElementAt(1090, x).Conn[y] = -1;
3006  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3007  }
3008  UnsetGaps = true;
3009  continue; // to next 'x'
3010  }
3011 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3012 // hence no more action needed on these Conns & CLks
3013  }
3014  } // else //gap jump
3015 
3016  } // for x...
3017  Utilities->CallLogPop(446);
3018  return(UnsetGaps);
3019 }
3020 
3021 // ---------------------------------------------------------------------------
3022 
3023 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3024 {
3025 // VecFile already open and its pointer at right place on calling
3026  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3027  int TempInt;
3028 
3029  TrackClear(1);
3030 // load track elements
3031  int NumberOfActiveElements = 0;
3032 
3033  GraphicsFollow = false;
3034  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3035  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3036 
3037  if(MarkerString[MarkerString.Length()] == '1')
3038  {
3039  GraphicsFollow = true;
3040  }
3041  for(int x = 0; x < NumberOfActiveElements; x++)
3042  {
3043  VecFile >> TempInt; // TrackVectorNumber, not used
3044  VecFile >> TempInt; // SpeedTag
3045  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3046  VecFile >> TempInt;
3047  TrackElement.HLoc = TempInt;
3048  VecFile >> TempInt;
3049  TrackElement.VLoc = TempInt;
3050  if(TrackElement.TrackType == GapJump)
3051  {
3052  VecFile >> TempInt;
3053  TrackElement.ConnLinkPos[0] = TempInt;
3054  VecFile >> TempInt;
3055  TrackElement.Conn[0] = TempInt;
3056  }
3057  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3058  {
3059  VecFile >> TempInt;
3060  TrackElement.Attribute = TempInt;
3061  }
3062  if(TrackElement.TrackType == SignalPost)
3063  {
3064  VecFile >> TempInt;
3065  if(TempInt == 0)
3066  {
3067  TrackElement.CallingOnSet = false;
3068  }
3069  else
3070  {
3071  TrackElement.CallingOnSet = true;
3072  }
3073  }
3074  VecFile >> TempInt;
3075  TrackElement.Length01 = TempInt;
3076  VecFile >> TempInt;
3077  TrackElement.Length23 = TempInt;
3078  VecFile >> TempInt;
3079  if((TempInt != -1) && (TempInt < 10))
3080  {
3081  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3082  }
3083  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3084  {
3085  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3086  }
3087  TrackElement.SpeedLimit01 = TempInt;
3088  VecFile >> TempInt;
3089  if((TempInt != -1) && (TempInt < 10))
3090  {
3091  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3092  }
3093  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3094  {
3095  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3096  }
3097  TrackElement.SpeedLimit23 = TempInt;
3098 
3099  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3100  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3101  SetElementID(0, TrackElement);
3102  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3103 // new for v0.6
3104  if(TrackElement.TrackType == SignalPost)
3105  {
3106  if(Marker[1] == '3')
3107  {
3108  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3109  }
3110  else if(Marker[1] == '2')
3111  {
3112  TrackElement.SigAspect = TTrackElement::TwoAspect;
3113  }
3114  else if(Marker[1] == 'G')
3115  {
3116  TrackElement.SigAspect = TTrackElement::GroundSignal;
3117  }
3118  else
3119  {
3120  TrackElement.SigAspect = TTrackElement::FourAspect;
3121  }
3122  }
3123  if(TrackElement.SpeedTag != 0)
3124  {
3125  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3126  }
3127  }
3128  int NumberOfInactiveElements = 0;
3129 
3130  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3131  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3132  for(int x = 0; x < NumberOfInactiveElements; x++)
3133  {
3134  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3135  VecFile >> TempInt; // SpeedTag
3136  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3137  VecFile >> TempInt;
3138  TrackElement.HLoc = TempInt;
3139  VecFile >> TempInt;
3140  TrackElement.VLoc = TempInt;
3141  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3142  SetElementID(3, TrackElement);
3143  TrackPush(9, TrackElement);
3144  Utilities->LoadFileString(VecFile); // marker
3145  }
3146  bool LocError = false; // needed for TryToConnectTrack but not used
3147  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3148 
3149  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3150  {
3151  SetTrackFinished(true);
3152  }
3153  else
3154  {
3155  SetTrackFinished(false);
3156  }
3157 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3158 // CheckMapAndInactiveTrack(8);
3159 // CheckLocationNameMultiMap(10);
3160  Utilities->CallLogPop(448);
3161 }
3162 
3163 // ---------------------------------------------------------------------------
3164 
3165 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3166 {
3167 // VecFile already open and its pointer at right place on calling
3168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3169 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3170 // & load into UserGraphicItem then store in UserGraphicVector
3171  UserGraphicVector.clear();
3172  TUserGraphicItem UGI;
3173  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3174 
3175  for(int x = 0; x < NumberOfGraphics; x++)
3176  {
3177  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3178  UGI.HPos = Utilities->LoadFileInt(VecFile);
3179  UGI.VPos = Utilities->LoadFileInt(VecFile);
3180  UGI.Width = 0; // provisional value
3181  UGI.Height = 0; // provisional value
3182  UGI.UserGraphic = NULL; // provisional value
3183  UserGraphicVector.push_back(UGI);
3184  }
3185 // now load the map & set Width, Height & TPicture*
3186  bool FileError = false;
3187 
3188  for(int x = 0; x < NumberOfGraphics; x++)
3189  {
3190  if(FileError)
3191  {
3192  break; // otherwise keeps going round the loop
3193  }
3194  UGI = UserGraphicVectorAt(0, x);
3195  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3196  {
3197  try
3198  {
3199 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3200  UGME.first = UGI.FileName;
3201  UGME.second = new TPicture;
3202  UGME.second->LoadFromFile(UGME.first); // errors caught below
3203  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3204  {
3205  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3206  }
3207  UGI.UserGraphic = UGME.second;
3208  UGI.Width = UGI.UserGraphic->Width;
3209  UGI.Height = UGI.UserGraphic->Height;
3210  UserGraphicVectorAt(1, x) = UGI;
3211  }
3212  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3213  {
3214  //message already sent in CheckUserGraphics
3215  FileError = true;
3216  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3217  if(!UserGraphicMap.empty())
3218  {
3219  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3220  {
3221  delete UGMIt->second;
3222  }
3223  UserGraphicMap.clear();
3224  }
3225  }
3226  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  }
3241  else
3242  {
3243  bool FoundInMap = false;
3244  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3245  {
3246  if(UGI.FileName == UGMIt->first) // already exists in map
3247  {
3248  UGI.UserGraphic = UGMIt->second;
3249  UGI.Width = UGI.UserGraphic->Width;
3250  UGI.Height = UGI.UserGraphic->Height;
3251  UserGraphicVectorAt(2, x) = UGI;
3252  FoundInMap = true;
3253  break;
3254  }
3255  }
3256  if(!FoundInMap)
3257  {
3258  try
3259  {
3261  UGME.first = UGI.FileName;
3262  UGME.second = new TPicture;
3263  UGME.second->LoadFromFile(UGME.first); // errors caught below
3264  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3265  {
3266  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3267  }
3268  UGI.UserGraphic = UGME.second;
3269  UGI.Width = UGI.UserGraphic->Width;
3270  UGI.Height = UGI.UserGraphic->Height;
3271  UserGraphicVectorAt(3, x) = UGI;
3272  }
3273  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3274  {
3275  //message already sent in CheckUserGraphics
3276  FileError = true;
3277  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3278  if(!UserGraphicMap.empty())
3279  {
3280  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3281  {
3282  delete UGMIt->second;
3283  }
3284  UserGraphicMap.clear();
3285  }
3286  }
3287  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3288  {
3289  //message already sent in CheckUserGraphics
3290  FileError = true;
3291  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3292  if(!UserGraphicMap.empty())
3293  {
3294  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3295  {
3296  delete UGMIt->second;
3297  }
3298  UserGraphicMap.clear();
3299  }
3300  }
3301  }
3302  }
3303  }
3304  Utilities->CallLogPop(2167);
3305 }
3306 
3307 // ---------------------------------------------------------------------------
3308 
3309 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3310 {
3311 // VecFile already open and its pointer at right place on calling
3312 // if GraphicsFollow true, then save Marker as **Active elements**1
3313 // save trackfinished flag
3314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3315  TTrackElement TrackElement, InactiveTrackElement;
3316 
3317 // save track elements
3318  Utilities->SaveFileInt(VecFile, TrackVector.size());
3319  if(GraphicsFollow)
3320  {
3321  VecFile << "**Active elements**1" << '\0' << '\n';
3322  }
3323  else
3324  {
3325  VecFile << "**Active elements**" << '\0' << '\n';
3326  }
3327  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3328  {
3329  TrackElement = TrackElementAt(1092, x);
3330  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3331  VecFile << TrackElement.SpeedTag << '\n';
3332  VecFile << TrackElement.HLoc << '\n';
3333  VecFile << TrackElement.VLoc << '\n';
3334  if(TrackElement.TrackType == GapJump)
3335  {
3336  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3337  VecFile << TrackElement.Conn[0] << '\n';
3338  }
3339  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3340  {
3341  VecFile << TrackElement.Attribute << '\n';
3342  }
3343  if(TrackElement.TrackType == SignalPost)
3344  {
3345  if(TrackElement.CallingOnSet)
3346  {
3347  VecFile << int(1) << '\n';
3348  }
3349  else
3350  {
3351  VecFile << int(0) << '\n';
3352  }
3353  }
3354  VecFile << TrackElement.Length01 << '\n';
3355  VecFile << TrackElement.Length23 << '\n';
3356  VecFile << TrackElement.SpeedLimit01 << '\n';
3357  VecFile << TrackElement.SpeedLimit23 << '\n';
3358  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3359  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3360 // new for v0.6
3361  if(TrackElement.TrackType == SignalPost)
3362  {
3363  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3364  {
3365  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3366  }
3367  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3368  {
3369  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3370  }
3371  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3372  {
3373  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374  }
3375  else // 4 aspect
3376  {
3377  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3378  }
3379  }
3380  else
3381  {
3382  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3383  }
3384  }
3385 
3386  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3387  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3388  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3389  {
3390  InactiveTrackElement = InactiveTrackElementAt(136, x);
3391  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3392  VecFile << InactiveTrackElement.SpeedTag << '\n';
3393  VecFile << InactiveTrackElement.HLoc << '\n';
3394  VecFile << InactiveTrackElement.VLoc << '\n';
3395  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3396  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3397  }
3398  Utilities->CallLogPop(449);
3399 }
3400 
3401 // ---------------------------------------------------------------------------
3402 
3403 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3404 {
3405 // VecFile already open and its pointer at right place on calling
3406 // check trackfinished flag
3407 // inactive elements follow immediately after active elements, no need to check for a marker between them
3408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3409  int TempInt;
3410 
3411  GraphicsFollow = false;
3412  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3413  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3414  {
3415  Utilities->CallLogPop(1513);
3416  return(false);
3417  }
3418 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3419  AnsiString MarkerString;
3420 
3421  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3422  {
3423  Utilities->CallLogPop(1758);
3424  return(false);
3425  }
3426  if(MarkerString[MarkerString.Length()] == '1')
3427  {
3428  GraphicsFollow = true;
3429  }
3430  for(int x = 0; x < NumberOfActiveElements; x++)
3431  {
3432  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3433  {
3434  Utilities->CallLogPop(1759);
3435  return(false);
3436  }
3437  VecFile >> TempInt;
3438  int SpeedTag = TempInt;
3439  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3440  {
3441  Utilities->CallLogPop(1514);
3442  return(false);
3443  }
3444  VecFile >> TempInt;
3445  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3446  {
3447  Utilities->CallLogPop(1495);
3448  return(false);
3449  }
3450  VecFile >> TempInt;
3451  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3452  {
3453  Utilities->CallLogPop(1497);
3454  return(false);
3455  }
3456  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3457  {
3458  VecFile >> TempInt;
3459  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3460  {
3461  Utilities->CallLogPop(1499);
3462  return(false);
3463  }
3464  VecFile >> TempInt;
3465  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3466  {
3467  Utilities->CallLogPop(1500);
3468  return(false);
3469  }
3470  }
3471  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3472  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3473  {
3474  VecFile >> TempInt;
3475  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3476  {
3477  Utilities->CallLogPop(1502);
3478  return(false);
3479  }
3480  }
3481  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3482  {
3483  VecFile >> TempInt;
3484  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3485  {
3486  Utilities->CallLogPop(1155);
3487  return(false);
3488  }
3489  }
3490  VecFile >> TempInt;
3491  if((TempInt < -1) || (TempInt > 999999)) // Length01
3492  {
3493  Utilities->CallLogPop(1503);
3494  return(false);
3495  }
3496  VecFile >> TempInt;
3497  if((TempInt < -1) || (TempInt > 999999)) // Length23
3498  {
3499  Utilities->CallLogPop(1504);
3500  return(false);
3501  }
3502  VecFile >> TempInt;
3503  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3504  {
3505  Utilities->CallLogPop(1505);
3506  return(false);
3507  }
3508  VecFile >> TempInt;
3509  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3510  {
3511  Utilities->CallLogPop(1506);
3512  return(false);
3513  }
3514  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3515  {
3516  Utilities->CallLogPop(1142);
3517  return(false); // LocationName
3518  }
3519  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3520  {
3521  Utilities->CallLogPop(1143);
3522  return(false); // ActiveTrackElementName
3523  }
3524  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3525  {
3526  Utilities->CallLogPop(1787);
3527  return(false); // marker
3528  }
3529  }
3530  int NumberOfInactiveElements = 0;
3531 
3532  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3533  if(NumberOfInactiveElements < 0) // No of active elements
3534  {
3535  Utilities->CallLogPop(1493);
3536  return(false);
3537  }
3538  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3539  {
3540  Utilities->CallLogPop(1764);
3541  return(false); // **Inactive elements** marker
3542  }
3543  for(int x = 0; x < NumberOfInactiveElements; x++)
3544  {
3545  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3546  {
3547  Utilities->CallLogPop(1765);
3548  return(false);
3549  }
3550  VecFile >> TempInt;
3551  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3552  {
3553  Utilities->CallLogPop(1494);
3554  return(false);
3555  }
3556  VecFile >> TempInt;
3557  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3558  {
3559  Utilities->CallLogPop(1496);
3560  return(false);
3561  }
3562  VecFile >> TempInt;
3563  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3564  {
3565  Utilities->CallLogPop(1498);
3566  return(false);
3567  }
3568  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3569  {
3570  Utilities->CallLogPop(1144);
3571  return(false); // LocationName
3572  }
3573  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3574  {
3575  Utilities->CallLogPop(1788);
3576  return(false); // marker
3577  }
3578  }
3579  Utilities->CallLogPop(1507);
3580  return(true);
3581 }
3582 
3583 // ---------------------------------------------------------------------------
3584 
3585 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3586 {
3587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3588  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3589 
3590  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3591  {
3592  Utilities->CallLogPop(2168);
3593  return(false);
3594  }
3595  // filename in Graphics folder, then HPos, then VPos
3596  AnsiString FileName = "", TempStr = "";
3597 
3598  for(int x = 0; x < NumberOfGraphics; x++)
3599  {
3600  TPicture *TempPicture = new TPicture;
3601  try
3602  {
3603  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3604  {
3605  Utilities->CallLogPop(2169);
3606  delete TempPicture;
3607  return(false);
3608  }
3609  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3610  delete TempPicture;
3611  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3612  {
3613  Utilities->CallLogPop(2170);
3614  return(false);
3615  }
3616  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3617  {
3618  Utilities->CallLogPop(2171);
3619  return(false);
3620  }
3621  }
3622  catch(const EInvalidGraphic &e) //non error catch
3623  {
3624  //move file pointer to end of graphic section for later checks in session files
3625  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3626  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3627  for(int y = x + 1; y < NumberOfGraphics; y++)
3628  {
3629  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3630  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3631  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3632  }
3633  ShowMessage(FileName +
3634  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3635  Utilities->CallLogPop(2172);
3636  delete TempPicture;
3637  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3638  }
3639  catch(const Exception &e) //non error catch
3640  {
3641  //move file pointer to end of graphic section for later checks in session files
3642  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3643  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3644  for(int y = x + 1; y < NumberOfGraphics; y++)
3645  {
3646  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3647  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3648  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3649  }
3650  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3651  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3652  Utilities->CallLogPop(2173);
3653  delete TempPicture;
3654  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3655  }
3656  }
3657  Utilities->CallLogPop(2174);
3658  return(true);
3659 }
3660 
3661 // ---------------------------------------------------------------------------
3662 
3663 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3664 {
3665  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3666  int VecSize = Track->BarriersDownVector.size();
3667 
3668  Utilities->SaveFileInt(OutFile, VecSize);
3669  for(int x = 0; x < VecSize; x++)
3670  {
3672  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3673  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3674  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3675  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3676  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3677  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3678  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3679  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3680  }
3681  Utilities->CallLogPop(1963);
3682 }
3683 
3684 // ---------------------------------------------------------------------------
3685 
3686 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3687 {
3688  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3689  int VecSize = Track->ChangingLCVector.size();
3690 
3691  Utilities->SaveFileInt(OutFile, VecSize);
3692  for(int x = 0; x < VecSize; x++)
3693  {
3695  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3696  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3697  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3698  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3699  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3700  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3701  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3702  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3703  }
3704  Utilities->CallLogPop(1980);
3705 }
3706 
3707 // ---------------------------------------------------------------------------
3708 
3709 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3710 {
3711  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3712  int VecSize = Utilities->LoadFileInt(VecFile);
3713 
3714  for(int x = 0; x < VecSize; x++)
3715  {
3716  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3717  {
3718  Utilities->CallLogPop(1970);
3719  return(false);
3720  }
3721  if(!Utilities->CheckFileBool(VecFile))
3722  {
3723  Utilities->CallLogPop(1971);
3724  return(false);
3725  }
3726  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3727  {
3728  Utilities->CallLogPop(1972);
3729  return(false);
3730  }
3731  if(!Utilities->CheckFileDouble(VecFile))
3732  {
3733  Utilities->CallLogPop(1973);
3734  return(false);
3735  }
3736  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3737  {
3738  Utilities->CallLogPop(1974);
3739  return(false);
3740  }
3741  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3742  {
3743  Utilities->CallLogPop(1975);
3744  return(false);
3745  }
3746  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3747  {
3748  Utilities->CallLogPop(1976);
3749  return(false);
3750  }
3751  if(!Utilities->CheckFileDouble(VecFile))
3752  {
3753  Utilities->CallLogPop(1977);
3754  return(false);
3755  }
3756  }
3757  Utilities->CallLogPop(1978);
3758  return(true);
3759 }
3760 
3761 // ---------------------------------------------------------------------------
3762 
3763 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3764 {
3765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3766  int VecSize = Utilities->LoadFileInt(VecFile);
3767 
3768  for(int x = 0; x < VecSize; x++)
3769  {
3770  TActiveLevelCrossing TALC;
3771  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3772  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3773  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3774  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3775  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3776  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3777  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3778  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3779  BarriersDownVector.push_back(TALC);
3780  }
3781  Utilities->CallLogPop(1979);
3782 }
3783 
3784 // ---------------------------------------------------------------------------
3785 
3786 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3787 /*
3788  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3789  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3790  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3791 */
3792 {
3793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3794  TTrackElement Next;
3795 
3796 // Disp->ClearDisplay();
3798  while(ReturnNextInactiveTrackElement(0, Next))
3799  {
3800  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3801  {
3802  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3803  {
3804  // only plot if on screen, to save time
3805  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3807  {
3808  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3809  }
3810  }
3811  }
3812  }
3813 
3814  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3815 
3816  NextTrackElementPtr = TrackVector.begin();
3817  while(ReturnNextTrackElement(0, Next))
3818  {
3819  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3820  {
3821  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3823  {
3824  if(Next.TrackType == Points)
3825  {
3826  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3827  }
3828  else if(Next.TrackType == SignalPost)
3829  {
3830  PlotSignal(9, Next, Disp);
3831  }
3832  else if(Next.TrackType == GapJump)
3833  {
3834  PlotGap(0, Next, Disp);
3835  }
3836  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3837  {
3838  PlotContinuation(0, Next, Disp);
3839  }
3840  else
3841  {
3842  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3843  }
3844  }
3845  }
3846  }
3847 
3848  if(BothPointFilletsAndBasicLCs)
3849  {
3851  while(ReturnNextInactiveTrackElement(4, Next))
3852  {
3853  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3854  {
3855  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3856  {
3857  // only plot if on screen, to save time, & OK as plotting one by one here
3858  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3860  {
3861  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3862  {
3863  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3864  }
3865  else
3866  {
3867  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3868  }
3869  }
3870  }
3871  }
3872  }
3873  }
3874  Disp->Update();
3875  Utilities->CallLogPop(468);
3876 }
3877 
3878 // ---------------------------------------------------------------------------
3879 
3880 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3881 {
3882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3883  if(UserGraphicVector.empty())
3884  {
3885  Utilities->CallLogPop(2175);
3886  return;
3887  }
3888  TUserGraphicItem UGI;
3889 
3890  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3891  {
3892  UGI = UserGraphicVectorAt(4, x);
3893  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3894  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3895  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3896  {
3897  Disp->PlotAndAddUserGraphic(0, UGI);
3898  }
3899  }
3900  Disp->Update();
3901  Utilities->CallLogPop(2176);
3902 }
3903 
3904 // ---------------------------------------------------------------------------
3905 
3906 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3907 /*
3908  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3909 */
3910 {
3911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3912 // need to change graphics back to black on white if have a dark background
3913  TColor OldTransparentColour = Utilities->clTransparent;
3914 
3916  {
3917  Utilities->clTransparent = TColor(0xFFFFFF); // white
3920  }
3921  TTrackElement Next;
3922 
3923  Bitmap->Canvas->CopyMode = cmSrcCopy;
3925  Graphics::TBitmap *GraphicOutput;
3926 
3927  while(ReturnNextInactiveTrackElement(2, Next))
3928  {
3929  GraphicOutput = Next.GraphicPtr;
3930  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3931  {
3932  if(Next.LocationName == "") // plot as named or unnamed (striped)
3933  {
3934  // default is not striped
3935  switch(Next.SpeedTag)
3936  {
3937  case 76: // t platform
3938  GraphicOutput = RailGraphics->gl76Striped;
3939  break;
3940 
3941  case 77: // h platform
3942  GraphicOutput = RailGraphics->bm77Striped;
3943  break;
3944 
3945  case 78: // v platform
3946  GraphicOutput = RailGraphics->bm78Striped;
3947  break;
3948 
3949  case 79: // r platform
3950  GraphicOutput = RailGraphics->gl79Striped;
3951  break;
3952 
3953  case 96: // concourse
3954  GraphicOutput = RailGraphics->ConcourseStriped;
3955  break;
3956 
3957  case 129: // v footbridge
3958  GraphicOutput = RailGraphics->gl129Striped;
3959  break;
3960 
3961  case 130: // h footbridge
3962  GraphicOutput = RailGraphics->gl130Striped;
3963  break;
3964 
3965  case 131: // non-station named loc
3966  GraphicOutput = RailGraphics->bmNameStriped;
3967  break;
3968 
3969  case 145: // v underpass
3970  GraphicOutput = RailGraphics->gl145Striped;
3971  break;
3972 
3973  case 146: // h underpass
3974  GraphicOutput = RailGraphics->gl146Striped;
3975  break;
3976 
3977  default:
3978  GraphicOutput = Next.GraphicPtr;
3979  break;
3980  }
3981  }
3982  if(Next.SpeedTag == 144) // level crossing
3983  {
3984  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3985  {
3986  GraphicOutput = RailGraphics->LCBothVer;
3987  }
3988  else
3989  {
3990  GraphicOutput = RailGraphics->LCBothHor;
3991  }
3992  }
3993  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3994  }
3995  }
3996 
3997  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3998 
3999 
4000  NextTrackElementPtr = TrackVector.begin();
4001  while(ReturnNextTrackElement(2, Next))
4002  {
4003  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4004  {
4005  if(Next.TrackType == Points) // plot both fillets
4006  {
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4008  if(Next.SpeedTag < 28)
4009  {
4010  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4012  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4014  }
4015  else if(Next.SpeedTag < 132)
4016  {
4017  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4018  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4019  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4020  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4021  }
4022  else
4023  {
4024  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4025  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4026  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4027  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4028  }
4029  }
4030  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4031  {
4032  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4033  {
4034  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4035  }
4036  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4037  {
4038  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4039  }
4040  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4041  {
4042  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4043  }
4044  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4045  {
4046  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4047  }
4048  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4049  {
4050  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4051  }
4052  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4053  {
4054  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4055  }
4056  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4057  {
4058  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4059  }
4060  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4061  {
4062  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4063  }
4064  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4065  {
4066  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4067  }
4068  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4069  {
4070  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4071  }
4072  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4073  {
4074  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4075  }
4076  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4077  {
4078  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4079  }
4080  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4081  {
4082  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4083  }
4084  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4085  {
4086  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4087  }
4088  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4089  {
4090  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4091  }
4092  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4093  {
4094  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4095  }
4096  }
4097  // below added for version 0.6, only stop signals to be drawn
4098  else if(Next.TrackType == SignalPost)
4099  {
4100  for(int x = 0; x < 40; x++)
4101  {
4102  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4103  {
4104  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4105  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4106  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4107  int HOffset = 0;
4108  if(Next.SpeedTag > 73)
4109  {
4110  HOffset = 5;
4111  }
4112  else if(Next.SpeedTag == 71)
4113  {
4114  HOffset = 9;
4115  }
4116  int VOffset = 0;
4117  if(Next.SpeedTag == 69)
4118  {
4119  VOffset = 9;
4120  }
4121  else if(Next.SpeedTag == 72)
4122  {
4123  VOffset = 5;
4124  }
4125  else if(Next.SpeedTag == 74)
4126  {
4127  VOffset = 5;
4128  }
4129  Graphics::TBitmap *GraphicPtr;
4130  if(Next.SpeedTag > 71)
4131  {
4132  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4133  }
4134  else if(Next.SpeedTag < 70)
4135  {
4136  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4137  }
4138  else
4139  {
4140  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4141  }
4142  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4143  // plot special signal platform if present
4144  Graphics::TBitmap* SignalPlatformGraphic;
4145  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4146  {
4147  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4148  }
4149  // now plot signal (double yellow overwrites most of signal platform if present)
4150  // below amended for version 0.6
4152  {
4153  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4154  }
4155  else if(Next.SigAspect == TTrackElement::TwoAspect)
4156  {
4157  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4158  }
4159  else if(Next.SigAspect == TTrackElement::GroundSignal)
4160  {
4161  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4162  }
4163  else // 4 aspect
4164  {
4165  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4166  }
4167  break;
4168  }
4169  }
4170  }
4171  else
4172  {
4173  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4174  }
4175  }
4176  }
4177  if(OldTransparentColour != clB5G5R5)
4178  {
4179  Utilities->clTransparent = OldTransparentColour; // restore
4182  }
4183  Utilities->CallLogPop(1533);
4184 }
4185 
4186 // ---------------------------------------------------------------------------
4187 
4188 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4189 {
4190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4191  if(UserGraphicVector.empty())
4192  {
4193  Utilities->CallLogPop(2192);
4194  return;
4195  }
4196  else
4197  {
4198  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4199  {
4200  Bitmap->Canvas->CopyMode = cmSrcCopy;
4201  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4202  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4203  }
4204  }
4205  Utilities->CallLogPop(2193);
4206 }
4207 
4208 // ---------------------------------------------------------------------------
4209 
4210 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4211 /*
4212  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4213  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4214 */
4215 {
4216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4217 // need to change graphics back to black on white if have a dark background
4218  TColor OldTransparentColour = Utilities->clTransparent;
4219 
4221  {
4222  Utilities->clTransparent = TColor(0xFFFFFF); // white
4225  }
4226  TTrackElement Next;
4227 
4228  Bitmap->Canvas->CopyMode = cmSrcCopy;
4230  Graphics::TBitmap *GraphicOutput;
4231 
4232  while(ReturnNextInactiveTrackElement(3, Next))
4233  {
4234  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4235  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4236  {
4237  if(Next.SpeedTag == 144) // level crossing
4238  {
4239  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4240  if(BaseElement == 1) // hor element
4241  {
4242  if(Next.Attribute == 1) // open to trains
4243  {
4244  GraphicOutput = RailGraphics->LCBothHor;
4245  }
4246  else // plot as closed to trains if in any other state
4247  {
4248  GraphicOutput = RailGraphics->LCBothVer;
4249  }
4250  }
4251  else // vert element
4252  {
4253  if(Next.Attribute == 1) // open to trains
4254  {
4255  GraphicOutput = RailGraphics->LCBothVer;
4256  }
4257  else // plot as closed to trains if in any other state
4258  {
4259  GraphicOutput = RailGraphics->LCBothHor;
4260  }
4261  }
4262  }
4263  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4264  }
4265  }
4266 
4267  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4268 
4269  NextTrackElementPtr = TrackVector.begin();
4270  while(ReturnNextTrackElement(3, Next))
4271  {
4272  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4273  {
4274  if(Next.TrackType == Points) // plot active fillet
4275  {
4276  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4277  if(Next.SpeedTag < 28)
4278  {
4279  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4281  }
4282  else if(Next.SpeedTag < 132)
4283  {
4284  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4286  }
4287  else
4288  {
4289  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4291  }
4292  if(Next.Failed) //added at v2.13.0
4293  {
4294  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4296  }
4297 
4298  }
4299  else if(Next.TrackType == GapJump) // plot as connected
4300  {
4301  if(Next.SpeedTag == 88)
4302  {
4303  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4304  }
4305  else if(Next.SpeedTag == 89)
4306  {
4307  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4308  }
4309  else if(Next.SpeedTag == 90)
4310  {
4311  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4312  }
4313  else if(Next.SpeedTag == 91)
4314  {
4315  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4316  }
4317  else if(Next.SpeedTag == 92)
4318  {
4319  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4320  }
4321  else if(Next.SpeedTag == 93)
4322  {
4323  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4324  }
4325  else if(Next.SpeedTag == 94)
4326  {
4327  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4328  }
4329  else if(Next.SpeedTag == 95)
4330  {
4331  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4332  }
4333  }
4334  else if(Next.TrackType == SignalPost) //plot in correct colour
4335  {
4336  for(int x = 0; x < 40; x++)
4337  {
4338  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4339  {
4340  //plot blank first, then plot platform if present - (always not striped for operating railway)
4341  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4342  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4343  int HOffset = 0;
4344  if(Next.SpeedTag > 73)
4345  {
4346  HOffset = 5;
4347  }
4348  else if(Next.SpeedTag == 71)
4349  {
4350  HOffset = 9;
4351  }
4352  int VOffset = 0;
4353  if(Next.SpeedTag == 69)
4354  {
4355  VOffset = 9;
4356  }
4357  else if(Next.SpeedTag == 72)
4358  {
4359  VOffset = 5;
4360  }
4361  else if(Next.SpeedTag == 74)
4362  {
4363  VOffset = 5;
4364  }
4365  Graphics::TBitmap *GraphicPtr;
4366  if(Next.SpeedTag > 71)
4367  {
4368  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4369  }
4370  else if(Next.SpeedTag < 70)
4371  {
4372  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4373  }
4374  else
4375  {
4376  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4377  }
4378  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4379  // plot special signal platform if present
4380  Graphics::TBitmap* SignalPlatformGraphic;
4381  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4382  {
4383  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4384  }
4385  if(!Next.Failed)
4386  {
4387  // now plot signal (double yellow overwrites most of signal platform if present)
4388  // below amended for version 0.6
4390  {
4391  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4392  }
4393  else if(Next.SigAspect == TTrackElement::TwoAspect)
4394  {
4395  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4396  }
4397  else if(Next.SigAspect == TTrackElement::GroundSignal)
4398  {
4399  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4400  }
4401  else // 4 aspect
4402  {
4403  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4404  }
4405  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4406  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4407  {
4408  if(Next.SpeedTag == 68)
4409  {
4410  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4411  }
4412  if(Next.SpeedTag == 69)
4413  {
4414  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4415  }
4416  if(Next.SpeedTag == 70)
4417  {
4418  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4419  }
4420  if(Next.SpeedTag == 71)
4421  {
4422  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4423  }
4424  if(Next.SpeedTag == 72)
4425  {
4426  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4427  }
4428  if(Next.SpeedTag == 73)
4429  {
4430  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4431  }
4432  if(Next.SpeedTag == 74)
4433  {
4434  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4435  }
4436  if(Next.SpeedTag == 75)
4437  {
4438  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4439  }
4440  }
4441  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4442  {
4443  for(int x = 0; x < 40; x++)
4444  {
4445  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4446  {
4447  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4448  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4449  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4450  // plot special signal platform if present
4451  Graphics::TBitmap* SignalPlatformGraphic;
4452  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4453  {
4454  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4455  }
4456  // now plot signal
4457  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4458  break;
4459  }
4460  }
4461  }
4462  break;
4463  }
4464  else //added at v2.13.0
4465  {
4467  {
4468  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4469  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4470  }
4471  else
4472  {
4473  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4474  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4475  }
4476  break;
4477  }
4478  }
4479  }
4480  }
4481  else
4482  {
4483  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4484  if(Next.Failed) //added at v2.13.0
4485  {
4486  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4488  }
4489  }
4490  }
4491  }
4492  if(OldTransparentColour != clB5G5R5)
4493  {
4494  Utilities->clTransparent = OldTransparentColour; // restore
4497  }
4498  Utilities->CallLogPop(1701);
4499 }
4500 
4501 // ---------------------------------------------------------------------------
4502 
4503 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4504 {
4505  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4506  for(unsigned int x = 0; x < TrackVector.size(); x++)
4507  {
4508  if(TrackElementAt(1093, x).TrackType == GapJump)
4509  {
4510  if(TrackElementAt(1094, x).Conn[0] > -1)
4511  {
4512  continue; // to next 'x' value as this element has already been set
4513  }
4514  // here if identify a GapJump element not yet set
4515  GapPos = x;
4516  GapHLoc = TrackElementAt(1095, x).HLoc;
4517  GapVLoc = TrackElementAt(1096, x).VLoc;
4518  // highlight it
4520  Utilities->CallLogPop(469);
4521  return(true);
4522  }
4523  }
4524  Utilities->CallLogPop(470);
4525  return(false);
4526 }
4527 
4528 // ---------------------------------------------------------------------------
4529 
4530 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4531 {
4532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4533  AnsiString(VLoc));
4534  int Position;
4535  TTrackElement TrackElement;
4536 
4537  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4538  {
4539  Utilities->CallLogPop(471);
4540  return(false); // not found
4541  }
4542  if(TrackElement.TrackType != GapJump)
4543  {
4544  Utilities->CallLogPop(472);
4545  return(false); // found something but not a gap
4546  }
4547  if(Position == GapPos)
4548  {
4549  Utilities->CallLogPop(473);
4550  return(false); // selected original gap
4551  }
4552  if(TrackElementAt(1097, Position).Conn[0] != -1)
4553  {
4554  Utilities->CallLogPop(474);
4555  return(false); // already selected
4556  }
4557  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4558  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4559  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4560  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4561 // now highlight the selected location
4562  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4563  Utilities->CallLogPop(475);
4564  return(true);
4565 }
4566 
4567 // ---------------------------------------------------------------------------
4568 
4569 bool TTrack::GapsUnset(int Caller)
4570 // returns true if there are gaps and any are unset
4571 {
4572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4573  if(TrackVector.size() == 0)
4574  {
4575  Utilities->CallLogPop(476);
4576  return(false);
4577  }
4578  for(unsigned int x = 0; x < TrackVector.size(); x++)
4579  {
4580  if(TrackElementAt(1102, x).TrackType == GapJump)
4581  {
4582  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4583  {
4584  Utilities->CallLogPop(477);
4585  return(true);
4586  }
4587  else // set, but may not have matching element, or that element may not be set
4588  {
4589  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4590  // check that the element pointed to by the gap link is a GapJump
4591  {
4592  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4593  Utilities->CallLogPop(1137);
4594  return(false);
4595  }
4596 // here if gap connection is itself a GapJump
4597  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4598  // check that the element pointed to by the gap link is a GapJump & that its gap link
4599  // points back to 'x'
4600  {
4601  Utilities->CallLogPop(478);
4602  return(true);
4603  }
4604 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4605  }
4606  } // if(TrackElementAt(, x).TrackType == GapJump)
4607 
4608  } // for x...
4609  Utilities->CallLogPop(479);
4610  return(false);
4611 }
4612 
4613 // ---------------------------------------------------------------------------
4614 
4615 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4616 {
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4618  for(unsigned int x = 0; x < TrackVector.size(); x++)
4619  {
4620  if(TrackElementAt(1110, x).TrackType == GapJump)
4621  {
4622  Utilities->CallLogPop(1105);
4623  return(false);
4624  }
4625  }
4626  Utilities->CallLogPop(1106);
4627  return(true);
4628 }
4629 
4630 // ---------------------------------------------------------------------------
4631 
4632 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4633 {
4634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4635  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4636  {
4637  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4638  {
4639  Utilities->CallLogPop(1107);
4640  return(false);
4641  }
4642  }
4643  for(unsigned int x = 0; x < TrackVector.size(); x++)
4644  {
4645  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4646  {
4647  Utilities->CallLogPop(1108);
4648  return(false);
4649  }
4650  }
4651  Utilities->CallLogPop(1109);
4652  return(true);
4653 }
4654 
4655 // ---------------------------------------------------------------------------
4656 
4658 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4659 // returns false otherwise or if there are no NamedLocationElements
4660 {
4661  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4662  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4663  {
4664  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4665  {
4666  if(InactiveTrackElementAt(139, x).LocationName == "")
4667  {
4668  Utilities->CallLogPop(1110);
4669  return(true);
4670  }
4671  }
4672  }
4673  for(unsigned int x = 0; x < TrackVector.size(); x++)
4674  {
4675  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4676  {
4677  if(TrackElementAt(1113, x).LocationName == "")
4678  {
4679  Utilities->CallLogPop(1111);
4680  return(true);
4681  }
4682  }
4683  }
4684  Utilities->CallLogPop(1112);
4685  return(false);
4686 }
4687 
4688 // ---------------------------------------------------------------------------
4689 
4690 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4691 {
4692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4693  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4694  Utilities->CallLogPop(480);
4695 }
4696 
4697 // ---------------------------------------------------------------------------
4698 
4700 {
4701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4702  if(TrackVector.size() == 0)
4703  {
4704  Utilities->CallLogPop(481);
4705  return;
4706  }
4707  for(unsigned int x = 0; x < TrackVector.size(); x++)
4708  {
4709  if(TrackElementAt(1114, x).TrackType == GapJump)
4710  {
4711  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4712  {
4713  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4714  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4715  {
4716  TrackElementAt(1118, x).Conn[0] = -1;
4717  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4718  continue; // to next 'x'
4719  }
4720 // here if gap connection is itself a GapJump
4721  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4722  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4723  // if not clear Conns & CLks
4724  {
4725  TrackElementAt(1121, x).Conn[0] = -1;
4726  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4727  continue; // to next 'x'
4728  }
4729 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4730 // hence no more action needed on these Conns & CLks
4731  }
4732  } // else //gap jump
4733 
4734  } // for x...
4735 // throw Exception("Test Exception");//test
4736  Utilities->CallLogPop(482);
4737 }
4738 
4739 // ---------------------------------------------------------------------------
4740 
4741 void TTrack::ResetSignals(int Caller)
4742 {
4743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4744  for(unsigned int x = 0; x < TrackVector.size(); x++)
4745  {
4746  if(TrackElementAt(1123, x).TrackType == SignalPost)
4747  {
4748  TrackElementAt(1124, x).Attribute = 0;
4749  TrackElementAt(1514, x).Failed = false;
4750  }
4751  }
4752  FailedSignalsVector.clear();
4753  Utilities->CallLogPop(483);
4754 }
4755 
4756 // ---------------------------------------------------------------------------
4757 
4758 void TTrack::ResetPoints(int Caller)
4759 {
4760  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4761  for(unsigned int x = 0; x < TrackVector.size(); x++)
4762  {
4763  if(TrackElementAt(1125, x).TrackType == Points)
4764  {
4765  TrackElementAt(1126, x).Attribute = 0;
4766  TrackElementAt(1515, x).Failed = false;
4767  }
4768  }
4769  FailedPointsVector.clear();
4770  Utilities->CallLogPop(484);
4771 }
4772 
4773 // ---------------------------------------------------------------------------
4774 
4775 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4776 {
4777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4778  for(unsigned int x = 0; x < TrackVector.size(); x++)
4779  {
4780  if(TrackElementAt(1554, x).TrackType == Simple)
4781  {
4782  TrackElementAt(1555, x).Failed = false;
4783  }
4784  }
4785  TSRVector.clear();
4786  Utilities->CallLogPop(2550);
4787 }
4788 
4789 // ---------------------------------------------------------------------------
4790 
4791 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4792 {
4793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4794  if(TrackVector.empty())
4795  {
4796  TrackMap.clear();
4797  Utilities->CallLogPop(485);
4798  return(true);
4799  }
4800 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4801  THVPair TrackMapKeyPair;
4802 
4803  NewVector.clear();
4804  TTrackMapIterator TrackMapPtr;
4805 
4806  if(!TrackMap.empty())
4807  {
4808  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4809  {
4810  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4811  }
4812  }
4813  if(NewVector.size() != TrackMap.size())
4814  {
4815  throw Exception("Error - Map & Vector different sizes");
4816  }
4817  unsigned int NonZeroCount = 0;
4818 
4819  for(unsigned int x = 0; x < TrackVector.size(); x++)
4820  {
4821  if(TrackElementAt(1127, x).TrackType != Erase)
4822  {
4823  NonZeroCount++;
4824  }
4825  }
4826  if(NewVector.size() != NonZeroCount)
4827  {
4828  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4829  }
4831  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4832  TTrackMapEntry TrackMapEntry;
4833 
4834  for(unsigned int x = 0; x < TrackVector.size(); x++)
4835  {
4836  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4837  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4838  TrackMapEntry.first = TrackMapKeyPair;
4839  TrackMapEntry.second = x;
4840  if(!(TrackMap.insert(TrackMapEntry).second))
4841  {
4842  throw Exception("Error - map insertion failure, TrackVector in error");
4843  }
4844  }
4845 // All track now relocated in TrackVector, reset all Conns & CLks
4846  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4847  {
4848  for(unsigned int y = 0; y < 4; y++)
4849  {
4850  TrackElementAt(1130, x).Conn[y] = -1;
4851  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4852  }
4853  }
4854  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4855  CheckMapAndTrack(4); // test
4856  CheckMapAndInactiveTrack(4); // test
4857  CheckLocationNameMultiMap(8); // test
4858  if(!ResetGapsFromGapMap(1))
4859  {
4860  Utilities->CallLogPop(489);
4861  return(false);
4862  }
4863  Utilities->CallLogPop(490);
4864  return(true);
4865 }
4866 
4867 // ---------------------------------------------------------------------------
4868 
4869 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4870 {
4871  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4872  GapMap.clear();
4873  THVPair GapMapKeyPair, GapMapValuePair;
4874  TGapMapEntry GapMapEntry;
4875 
4876  for(unsigned int x = 0; x < TrackVector.size(); x++)
4877  {
4878  if(TrackElementAt(1132, x).TrackType == GapJump)
4879  {
4880  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4881  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4882  GapMapEntry.first = GapMapKeyPair;
4883  if(TrackElementAt(1135, x).Conn[0] == -1)
4884  {
4885  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4886  }
4887  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4888  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4889  GapMapEntry.second = GapMapValuePair;
4890  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4891  {
4892  GapMap.insert(GapMapEntry);
4893  }
4894  }
4895  }
4896  Utilities->CallLogPop(492);
4897 }
4898 
4899 // ---------------------------------------------------------------------------
4900 
4901 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4902 {
4903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4904 
4905 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4906  LocError = false;
4907  bool TrackElementPositionsOK = true;
4908 
4909  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4910  {
4911  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4912  {
4913  continue; // skip blank elements
4914  }
4915 // check footcrossing linkages
4916  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4917  {
4918  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4919  {
4920  ShowMessage(
4921  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4922  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4923  "can't connect to an underpass or vice versa)");
4924  HLoc = TrackElementAt(1141, x).HLoc;
4925  VLoc = TrackElementAt(1142, x).VLoc;
4926  LocError = true;
4927  Utilities->CallLogPop(493);
4928  return(false);
4929  }
4930  }
4931  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4932  {
4933  if(TrackElementAt(1143, x).Link[y] <= 0)
4934  {
4935  continue; // no link
4936  }
4937  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4938  {
4939  continue; // buffer
4940  }
4941  if(TrackElementAt(1146, x).Config[y] == Gap)
4942  {
4943  continue; // gaps set later from GapMap
4944  }
4945  // get required H & V for track element joining link 'y'
4946  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4947  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4948  // find track element if present
4949  bool ConnectionFoundFlag;
4950  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4951  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4952  {
4953  ShowMessage("Can't have a track element adjacent to a continuation exit");
4954  HLoc = TrackElementAt(1152, x).HLoc;
4955  VLoc = TrackElementAt(1153, x).VLoc;
4956  LocError = true;
4957  if(FinalCall)
4958  {
4959  throw Exception("Error in final track linkage - continuation adjacent to another element");
4960  }
4961  Utilities->CallLogPop(1539);
4962  return(false);
4963  }
4964  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4965  {
4966  continue;
4967  }
4968  if(ConnectionFoundFlag)
4969  {
4970  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4971  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4972 
4973  bool ExitSignal = false;
4974  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
4975  {
4976  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
4977  {
4978  ExitSignal = true;
4979  }
4980  }
4981  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4982  {
4983  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4984  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4985  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4986  TrackElementPositionsOK = false;
4987  }
4988  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4989  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4990  {
4991  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4992  // need room for a train (2 elements) without fouling points or signals
4993  TrackElementPositionsOK = false;
4994  }
4995  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4996  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4997  {
4998  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4999  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5000  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5001  // be named but needs the adjacent element named too
5002  TrackElementPositionsOK = false;
5003  }
5004  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5005  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5006  {
5007  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5008  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5009  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5010  TrackElementPositionsOK = false;
5011  }
5012 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5013 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
5014  {
5015  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5016  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5017  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5018  TrackElementPositionsOK = false;
5019  }*/
5020  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5021  {
5022  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5023  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5024  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5025  TrackElementPositionsOK = false;
5026  }
5027  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5028  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5029  {
5030  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5031  TrackElementPositionsOK = false;
5032  }
5033  // if failed then set the invert values for the offending element
5034  if(!TrackElementPositionsOK)
5035  {
5036  HLoc = TrackElementAt(1183, x).HLoc;
5037  VLoc = TrackElementAt(1184, x).VLoc;
5038  LocError = true;
5039  if(FinalCall)
5040  {
5041  throw Exception("Error in track element positions in FinalCall");
5042  }
5043  Utilities->CallLogPop(494);
5044  return(false);
5045  }
5046  }
5047  // no 'else' here, if there's no link then will be picked up in 2nd pass
5048  }
5049  } // for(unsigned int x=0;x<TrackVector.size();x++)
5050 
5051 
5052 //2nd pass - looking for missing connections
5053  LocError = false;
5054  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5055  {
5056  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5057  {
5058  continue; // skip blank elements
5059  }
5060  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5061  {
5062  if(TrackElementAt(1440, x).Link[y] <= 0)
5063  {
5064  continue; // no link
5065  }
5066  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5067  {
5068  continue; // buffer
5069  }
5070  if(TrackElementAt(1443, x).Config[y] == Gap)
5071  {
5072  continue; // gaps set later from GapMap
5073  }
5074  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5075  {
5076  continue; //continuation
5077  }
5078  // get required H & V for track element joining link 'y'
5079  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5080  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5081  // find track element if present
5082  bool ConnectionFoundFlag;
5083  bool LinkMatchFound = false;
5084  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag);
5085  // if there isn't a connection set the invert values for the offending element
5086  if(ConnectionFoundFlag) //set the ConnLinkPos values
5087  {
5088  for(unsigned int a = 0; a < 4; a++)
5089  {
5090  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5091  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5092  {
5093  TrackElementAt(1182, x).ConnLinkPos[y] = a;
5094  // note - this ensures that if the connecting element is a leading point
5095  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5096  // (Points have the same link value for both [0] and [2])
5097  LinkMatchFound = true;
5098  break; // stop after first find or will find later link for leading point
5099  }
5100  }
5101  if(!LinkMatchFound)
5102  {
5103  HLoc = TrackElementAt(1446, x).HLoc;
5104  VLoc = TrackElementAt(1447, x).VLoc;
5105  LocError = true;
5106  if(FinalCall)
5107  {
5108  throw Exception("Error in final track linkage - - no matching link found");
5109  }
5110  Utilities->CallLogPop(495);
5111  return(false);
5112  }
5113  }
5114  else //error
5115  {
5116  HLoc = TrackElementAt(1185, x).HLoc;
5117  VLoc = TrackElementAt(1186, x).VLoc;
5118  LocError = true;
5119  if(FinalCall)
5120  {
5121  throw Exception("Error in final track linkage - connection not found");
5122  }
5123  Utilities->CallLogPop(2443);
5124  return(false);
5125  }
5126  }
5127  }
5128 //end of 2nd pass
5129 
5130  if(FinalCall)
5131  {
5133  }
5134 
5135 // confirmatiory checks that all ok - or throw error
5136  bool ConnErrorFlag = false;
5137 
5138  for(unsigned int x = 0; x < TrackVector.size(); x++)
5139  {
5140  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5141  {
5142  ConnErrorFlag = true;
5143  }
5144  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5145  {
5146  ConnErrorFlag = true;
5147  }
5148  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5149  {
5150  ConnErrorFlag = true;
5151  }
5152  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5153  {
5154  ConnErrorFlag = true;
5155  }
5156  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5157  {
5158  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5159  {
5160  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
5161  {
5162  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5163  }
5164  }
5165  }
5166  }
5167  if(ConnErrorFlag)
5168  {
5169  if(FinalCall)
5170  {
5171  throw Exception("ConnError in LinkTrack - Final");
5172  }
5173  else
5174  {
5175  throw Exception("ConnError in LinkTrack - Precheck");
5176  }
5177  }
5178  bool CLkErrorFlag = false;
5179 
5180  for(unsigned int x = 0; x < TrackVector.size(); x++)
5181  {
5182  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5183  {
5184  CLkErrorFlag = true;
5185  }
5186  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5187  {
5188  CLkErrorFlag = true;
5189  }
5190  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5191  {
5192  CLkErrorFlag = true;
5193  }
5194  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5195  {
5196  CLkErrorFlag = true;
5197  }
5198  }
5199 
5200  if(CLkErrorFlag)
5201  {
5202  if(FinalCall)
5203  {
5204  throw Exception("CLkError in LinkTrack - Final");
5205  }
5206  else
5207  {
5208  throw Exception("CLkError in LinkTrack - Precheck");
5209  }
5210  }
5211 
5212 // set element lengths to min of 10m
5213  for(unsigned int x = 0; x < TrackVector.size(); x++)
5214  {
5215  if(TrackElementAt(1214, x).TrackType == Erase)
5216  {
5217  continue; // skip blank elements
5218  }
5219  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5220  {
5221  TrackElementAt(1216, x).Length01 = 10;
5222  }
5223  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5224  {
5225  TrackElementAt(1219, x).Length23 = 10;
5226  }
5227  }
5228 
5229  if(FinalCall) // ONLY at FinalCall, no point calling twice
5230  {
5231  CalcHLocMinEtc(3);
5232  }
5233 
5234  Utilities->CallLogPop(497);
5235  return(true);
5236 }
5237 
5238 // ---------------------------------------------------------------------------
5239 
5240 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5241 {
5242  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5243  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5244  {
5245  if(TrackElementAt(1220, x).TrackType == Erase)
5246  {
5247  continue; // skip blank elements
5248 
5249  }
5250 // check footcrossing linkages
5251  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5252  {
5253  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5254  {
5255  Utilities->CallLogPop(1127);
5256  return(false);
5257  }
5258  }
5259  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5260  {
5261  if(TrackElementAt(1223, x).Link[y] <= 0)
5262  {
5263  continue; // no link
5264  }
5265  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5266  {
5267  continue; // buffer
5268  }
5269  if(TrackElementAt(1226, x).Config[y] == Gap)
5270  {
5271  continue; // gaps set later from GapMap
5272 
5273  }
5274  // get required H & V for track element joining link 'y'
5275  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5276  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5277  // find track element if present
5278  bool ConnectionFoundFlag;
5279  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5280  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5281  {
5282  if(FinalCall)
5283  {
5284  throw Exception("Error in final track linkage - continuation adjacent to another element");
5285  }
5286  Utilities->CallLogPop(1540);
5287  return(false);
5288  }
5289  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5290  {
5291  continue;
5292  }
5293  if(ConnectionFoundFlag)
5294  {
5295  TrackElementAt(1234, x).Conn[y] = VecPos;
5296  bool LinkFoundFlag = false;
5297  // find connecting link in the newly found track element if there is one & make checks
5298  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5299  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5300  {
5301  Utilities->CallLogPop(1541);
5302  return(false);
5303  }
5304  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5305  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5306  {
5307  Utilities->CallLogPop(1542);
5308  return(false);
5309  }
5310  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5311  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5312  {
5313  Utilities->CallLogPop(1543);
5314  return(false);
5315  }
5316  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5317  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5318  {
5319  Utilities->CallLogPop(1981);
5320  return(false);
5321  }
5322 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5323  else if(TrackElementAt(, x).TrackType == Continuation)
5324  {
5325  int H = TrackElementAt(, x).HLoc;
5326  int V = TrackElementAt(, x).VLoc;
5327  bool FoundFlag = false;
5328  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5329  if(FoundFlag)
5330  {
5331  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5332  {
5333  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5334  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5335  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5336  if(FoundFlag)
5337  {
5338  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5339  {
5340  Utilities->CallLogPop();
5341  return false;
5342  }
5343  }
5344  else
5345  {
5346  Utilities->CallLogPop();
5347  return false;
5348  }
5349  }
5350  }
5351  }
5352 */
5353  for(unsigned int a = 0; a < 4; a++)
5354  {
5355  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5356  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5357  {
5358  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5359  // note - this ensures that if the connecting element is a leading point
5360  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5361  // (Points have the same link value for both [0] and [2])
5362  LinkFoundFlag = true;
5363  break; // stop after first find or will find later link for leading point
5364  }
5365  }
5366  if(!LinkFoundFlag)
5367  {
5368  if(FinalCall)
5369  {
5370  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5371  }
5372  Utilities->CallLogPop(1128);
5373  return(false);
5374  }
5375  }
5376  else // if(ConnectionFoundFlag)
5377  {
5378  if(FinalCall)
5379  {
5380  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5381  }
5382  Utilities->CallLogPop(1129);
5383  return(false);
5384  }
5385  }
5386  } // for(unsigned int x=0;x<TrackVector.size();x++)
5387 
5388  if(FinalCall)
5389  {
5391  }
5392 // final check
5393  bool ConnErrorFlag = false;
5394 
5395  for(unsigned int x = 0; x < TrackVector.size(); x++)
5396  {
5397  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5398  {
5399  ConnErrorFlag = true;
5400  }
5401  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5402  {
5403  ConnErrorFlag = true;
5404  }
5405  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5406  {
5407  ConnErrorFlag = true;
5408  }
5409  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5410  {
5411  ConnErrorFlag = true;
5412  }
5413  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5414  {
5415  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5416  {
5417  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5418  {
5419  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5420  }
5421  }
5422  }
5423  }
5424  if(ConnErrorFlag)
5425  {
5426  if(FinalCall)
5427  {
5428  throw Exception("ConnError in LinkTrack - Final");
5429  }
5430  else
5431  {
5432  throw Exception("ConnError in LinkTrack - Precheck");
5433  }
5434  }
5435  bool CLkErrorFlag = false;
5436 
5437  for(unsigned int x = 0; x < TrackVector.size(); x++)
5438  {
5439  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5440  {
5441  CLkErrorFlag = true;
5442  }
5443  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5444  {
5445  CLkErrorFlag = true;
5446  }
5447  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5448  {
5449  CLkErrorFlag = true;
5450  }
5451  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5452  {
5453  CLkErrorFlag = true;
5454  }
5455  }
5456 
5457  if(CLkErrorFlag)
5458  {
5459  if(FinalCall)
5460  {
5461  throw Exception("CLkError in LinkTrack - Final");
5462  }
5463  else
5464  {
5465  throw Exception("CLkError in LinkTrack - Precheck");
5466  }
5467  }
5468 // set element lengths to min of 10m
5469  for(unsigned int x = 0; x < TrackVector.size(); x++)
5470  {
5471  if(TrackElementAt(1284, x).TrackType == Erase)
5472  {
5473  continue; // skip blank elements
5474  }
5475  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5476  {
5477  TrackElementAt(1286, x).Length01 = 10;
5478  }
5479  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5480  {
5481  TrackElementAt(1289, x).Length23 = 10;
5482  }
5483  }
5484 
5485  if(FinalCall) // ONLY at FinalCall, no point calling twice
5486  {
5487  CalcHLocMinEtc(7);
5488  }
5489  Utilities->CallLogPop(1130);
5490  return(true);
5491 }
5492 
5493 // ---------------------------------------------------------------------------
5494 
5495 bool TTrack::IsTrackLinked(int Caller) // not used any more
5496 {
5497  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5498  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5499  {
5500  if(TrackElementAt(1290, x).TrackType == Erase)
5501  {
5502  Utilities->CallLogPop(498);
5503  return(false);
5504  }
5505 // check foot linkages
5506  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5507  {
5508  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5509  {
5510  Utilities->CallLogPop(499);
5511  return(false);
5512  }
5513  }
5514  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5515  {
5516  if(TrackElementAt(1293, x).Link[y] <= 0)
5517  {
5518  continue; // no link
5519  }
5520  if(TrackElementAt(1294, x).Config[y] == End)
5521  {
5522  continue; // buffer or continuation
5523  }
5524  if(TrackElementAt(1295, x).Config[y] == Gap)
5525  {
5526  continue; // gaps set later from GapMap
5527 
5528  }
5529  // get required H & V for track element joining link 'y'
5530  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5531  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5532  // find track element if present
5533  bool ConnectionFoundFlag = false;
5534  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5535  if(ConnectionFoundFlag)
5536  {
5537  TrackElementAt(1300, x).Conn[y] = VecPos;
5538  // find connecting link in the newly found track element if there is one & make buffer check
5539  bool LinkFoundFlag = false;
5540  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5541  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5542  {
5543  Utilities->CallLogPop(500);
5544  return(false);
5545  }
5546  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5547  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5548  {
5549  Utilities->CallLogPop(501);
5550  return(false);
5551  }
5552  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5553  {
5554  Utilities->CallLogPop(502);
5555  return(false);
5556  }
5557  else
5558  {
5559  for(unsigned int a = 0; a < 4; a++)
5560  {
5561  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5562  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5563  {
5564  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5565  // note - this ensures that if the connecting element is a leading point
5566  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5567  // (Points have the same link value for both [0] and [2])
5568  LinkFoundFlag = true;
5569  break; // stop after first find or will find later link for leading point
5570  }
5571  }
5572  }
5573  if(!LinkFoundFlag)
5574  {
5575  Utilities->CallLogPop(503);
5576  return(false);
5577  }
5578  }
5579  else // if(ConnectionFoundFlag)
5580  {
5581  Utilities->CallLogPop(504);
5582  return(false);
5583  }
5584  }
5585  } // for(unsigned int x=0;x<TrackVector.size();x++)
5586 
5587 // final check
5588  bool ConnErrorFlag = false;
5589 
5590  for(unsigned int x = 0; x < TrackVector.size(); x++)
5591  {
5592  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5593  {
5594  ConnErrorFlag = true;
5595  }
5596  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5597  {
5598  ConnErrorFlag = true;
5599  }
5600  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5601  {
5602  ConnErrorFlag = true;
5603  }
5604  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5605  {
5606  ConnErrorFlag = true;
5607  }
5608  }
5609  if(ConnErrorFlag)
5610  {
5611  Utilities->CallLogPop(505);
5612  return(false);
5613  }
5614  bool CLkErrorFlag = false;
5615 
5616  for(unsigned int x = 0; x < TrackVector.size(); x++)
5617  {
5618  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5619  {
5620  CLkErrorFlag = true;
5621  }
5622  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5623  {
5624  CLkErrorFlag = true;
5625  }
5626  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5627  {
5628  CLkErrorFlag = true;
5629  }
5630  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5631  {
5632  CLkErrorFlag = true;
5633  }
5634  }
5635 
5636  if(CLkErrorFlag)
5637  {
5638  Utilities->CallLogPop(506);
5639  return(false);
5640  }
5641  Utilities->CallLogPop(507);
5642  return(true);
5643 }
5644 
5645 // ---------------------------------------------------------------------------
5646 
5648 {
5649  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5650  int Position1, Position2;
5651  TTrackElement TrackElement1, TrackElement2;
5652  TGapMapIterator GapMapPtr;
5653 
5654  if(!GapMap.empty())
5655  {
5656  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5657  {
5658  int HLoc1 = GapMapPtr->first.first;
5659  int VLoc1 = GapMapPtr->first.second;
5660  int HLoc2 = GapMapPtr->second.first;
5661  int VLoc2 = GapMapPtr->second.second;
5662  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5663  {
5664  throw Exception("Failed to find H & V for gap1, GapMap in error");
5665  }
5666  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5667  {
5668  throw Exception("Failed to find H & V for gap2, GapMap in error");
5669  }
5670  if(TrackElementAt(9, Position1).TrackType != GapJump)
5671  {
5672  throw Exception("Element at Pos1 not a gap, GapMap in error");
5673  }
5674  if(TrackElementAt(10, Position2).TrackType != GapJump)
5675  {
5676  throw Exception("Element at Pos2 not a gap, GapMap in error");
5677  }
5678  TrackElementAt(11, Position1).Conn[0] = Position2;
5679  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5680  TrackElementAt(13, Position2).Conn[0] = Position1;
5681  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5682  }
5683  }
5684  Utilities->CallLogPop(510);
5685  return(true);
5686 }
5687 
5688 // ---------------------------------------------------------------------------
5689 
5690 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5691 {
5692 // TIMPair MapEntry;
5693  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5694  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5695  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5696  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5697  TLocationNameMultiMapEntry LocationNameEntry;
5698 
5699  LocationNameEntry.first = TrackElement.LocationName;
5700  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5701  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5702  {
5703 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5704 // could arise when loading old railways with multiple NonStationNamedLocs
5705  bool FoundFlag = false;
5706  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5707  if(FoundFlag)
5708  {
5709  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5710  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5711  {
5712  Utilities->CallLogPop(1813);
5713  return;
5714  }
5715  }
5716  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5717  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5718  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5719  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5720  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5721  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5722  if(TrackElement.FixedNamedLocationElement)
5723  {
5724  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5725  LocationNameMultiMap.insert(LocationNameEntry);
5726  }
5727  if(TrackElement.HLoc < HLocMin)
5728  {
5729  HLocMin = TrackElement.HLoc;
5730  }
5731  if(TrackElement.HLoc > HLocMax)
5732  {
5733  HLocMax = TrackElement.HLoc;
5734  }
5735  if(TrackElement.VLoc < VLocMin)
5736  {
5737  VLocMin = TrackElement.VLoc;
5738  }
5739  if(TrackElement.VLoc > VLocMax)
5740  {
5741  VLocMax = TrackElement.VLoc;
5742  }
5743  }
5744  else
5745  {
5746 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5747 // shouldn't arise but leave in as a safeguard
5748  bool FoundFlag = false;
5749  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5750  if(FoundFlag)
5751  {
5752  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5753  {
5754  Utilities->CallLogPop(1814);
5755  return;
5756  }
5757  }
5758  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5759  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5760  {
5761  TrackMapKeyPair.first = TrackElement.HLoc;
5762  TrackMapKeyPair.second = TrackElement.VLoc;
5763  TrackMapEntry.first = TrackMapKeyPair;
5764  TrackMapEntry.second = TrackVector.size() - 1;
5765  TrackMap.insert(TrackMapEntry);
5766  if(TrackElement.FixedNamedLocationElement)
5767  {
5768  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5769  LocationNameMultiMap.insert(LocationNameEntry);
5770  }
5771  if(TrackElement.HLoc < HLocMin)
5772  {
5773  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5774  }
5775  if(TrackElement.HLoc > HLocMax)
5776  {
5777  HLocMax = TrackElement.HLoc;
5778  }
5779  if(TrackElement.VLoc < VLocMin)
5780  {
5781  VLocMin = TrackElement.VLoc;
5782  }
5783  if(TrackElement.VLoc > VLocMax)
5784  {
5785  VLocMax = TrackElement.VLoc;
5786  }
5787  }
5788  }
5789 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5790 // CheckMapAndInactiveTrack(6);//test
5791 
5792 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5793 // with the Platforms until layout fully loaded
5794  Utilities->CallLogPop(511);
5795 }
5796 
5797 // ---------------------------------------------------------------------------
5798 
5799 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5800 {
5801  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5802  AnsiString(VLoc));
5803  THVPair TrackMapKeyPair;
5804 
5805  FoundFlag = false;
5806  TTrackMapIterator TrackMapPtr;
5807 
5808  TrackMapKeyPair.first = HLoc;
5809  TrackMapKeyPair.second = VLoc;
5810  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5811  if(TrackMapPtr == TrackMap.end())
5812  {
5813  Utilities->CallLogPop(512);
5814  return(-1); // nothing found
5815  }
5816  else
5817  {
5818  FoundFlag = true;
5819  Utilities->CallLogPop(513);
5820  return(TrackMapPtr->second);
5821  }
5822 }
5823 
5824 // ---------------------------------------------------------------------------
5825 
5826 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5827 {
5828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5829  AnsiString(VLoc));
5830  THVPair TrackMapKeyPair;
5831  TTrackMapIterator TrackMapPtr;
5832 
5833  TrackMapKeyPair.first = HLoc;
5834  TrackMapKeyPair.second = VLoc;
5835  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5836  if(TrackMapPtr == TrackMap.end())
5837  {
5838  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5839  throw Exception(Message);
5840  }
5841  else
5842  {
5843  Utilities->CallLogPop(1943);
5844  return(TrackElementAt(871, TrackMapPtr->second));
5845  }
5846 }
5847 
5848 // ---------------------------------------------------------------------------
5849 
5850 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5851 { //modded at v2.9.2 to make Map & Vector references
5852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5853  AnsiString(VLoc));
5854  THVPair MapKeyPair;
5855  TTrackMapIterator MapPtr;
5856 
5857  MapKeyPair.first = HLoc;
5858  MapKeyPair.second = VLoc;
5859  MapPtr = Map.find(MapKeyPair);
5860  if(MapPtr == Map.end())
5861  {
5862  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5863  throw Exception(Message);
5864  }
5865  else
5866  {
5867  Utilities->CallLogPop(2280);
5868  return(Vector.at(MapPtr->second));
5869  }
5870 }
5871 
5872 // ---------------------------------------------------------------------------
5873 
5875 {
5876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5877  AnsiString(VLoc));
5878  THVPair InactiveTrackMapKeyPair;
5879  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5880 
5881  InactiveTrackMapKeyPair.first = HLoc;
5882  InactiveTrackMapKeyPair.second = VLoc;
5883  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5884  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5885  {
5886  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5887  throw Exception(Message);
5888  }
5889  else
5890  {
5891  Utilities->CallLogPop(1949);
5892  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5893  }
5894 }
5895 
5896 // ---------------------------------------------------------------------------
5897 
5898 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5899 {
5900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5901  bool Present = true;
5902  THVPair TrackMapKeyPair;
5903  TTrackMapIterator TrackMapPtr;
5904 
5905  TrackMapKeyPair.first = HLoc;
5906  TrackMapKeyPair.second = VLoc;
5907  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5908  if(TrackMapPtr == TrackMap.end())
5909  {
5910  Present = false;
5911  }
5912  Utilities->CallLogPop(2057);
5913  return(Present);
5914 }
5915 
5916 // ---------------------------------------------------------------------------
5917 
5918 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5919 {
5920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5921  AnsiString(VLoc));
5922  bool Present = true;
5923  THVPair InactiveTrackMapKeyPair;
5924  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5925 
5926  InactiveTrackMapKeyPair.first = HLoc;
5927  InactiveTrackMapKeyPair.second = VLoc;
5928  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5929  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5930  {
5931  Present = false;
5932  }
5933  Utilities->CallLogPop(2058);
5934  return(Present);
5935 }
5936 
5937 // ---------------------------------------------------------------------------
5938 
5939 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5940 // max number of elements is 2, for platforms
5941 // note that both elements of RetPair may be the same, if only one present in map
5942 {
5943  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5944  AnsiString(VLoc));
5945  THVPair InactiveTrackMapKeyPair;
5946  TIMPair RetPair;
5947  TInactiveTrackRange InactiveTrackRange;
5948 
5949  FoundFlag = false;
5950  InactiveTrackMapKeyPair.first = HLoc;
5951  InactiveTrackMapKeyPair.second = VLoc;
5952  if(InactiveTrack2MultiMap.empty())
5953  {
5954  RetPair.first = 0;
5955  RetPair.second = 0;
5956  Utilities->CallLogPop(1815);
5957  return(RetPair); // map empty
5958  }
5959  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5960  if(InactiveTrackRange.first == InactiveTrackRange.second)
5961  {
5962  RetPair.first = 0;
5963  RetPair.second = 0;
5964  Utilities->CallLogPop(514);
5965  return(RetPair); // nothing found
5966  }
5967  else
5968  {
5969  RetPair.first = InactiveTrackRange.first->second;
5970  RetPair.second = (--InactiveTrackRange.second)->second;
5971  FoundFlag = true;
5972  Utilities->CallLogPop(515);
5973  return(RetPair);
5974  }
5975 }
5976 
5977 // ---------------------------------------------------------------------------
5978 
5979 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
5980 {
5981 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5982  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5983  AnsiString(DivergingPosition));
5984  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5985  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5986  int SpeedTag1 = T1.SpeedTag;
5987  int SpeedTag2 = T2.SpeedTag;
5988 
5989  if((T1.Attribute) != (T2.Attribute))
5990  {
5991  Utilities->CallLogPop(516);
5992  return(false);
5993  }
5994  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5995  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5996  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5997  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5998  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5999  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6000  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6001  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6002  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6003  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6004  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6005  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6006  {
6007  Utilities->CallLogPop(517);
6008  return(true);
6009  }
6010  else
6011  {
6012  Utilities->CallLogPop(518);
6013  return(false);
6014  }
6015 }
6016 
6017 // ---------------------------------------------------------------------------
6018 
6019 /*
6020  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6021  {
6022  if(lower.second < higher.second) return true;
6023  else if(lower.second > higher.second) return false;
6024  else if(lower.second == higher.second)
6025  {
6026  if(lower.first < higher.first) return true;
6027  }
6028  return false;
6029  }
6030 */
6031 // ---------------------------------------------------------------------------
6032 
6033 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6034 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6035 {
6036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6037  if(TrackElement.TrackType != GapJump)
6038  {
6039  throw Exception("Error, Wrong track type in PlotGap");
6040  }
6041  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6042  {
6043  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6044  }
6045  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6046  {
6047  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6048  }
6049  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6050  {
6051  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6052  }
6053  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6054  {
6055  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6056  }
6057  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6058  {
6059  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6060  }
6061  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6062  {
6063  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6064  }
6065  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6066  {
6067  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6068  }
6069  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6070  {
6071  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6072  }
6073  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6074  {
6075  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6076  }
6077  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6078  {
6079  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6080  }
6081  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6082  {
6083  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6084  }
6085  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6086  {
6087  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6088  }
6089  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6090  {
6091  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6092  }
6093  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6094  {
6095  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6096  }
6097  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6098  {
6099  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6100  }
6101  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6102  {
6103  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6104  }
6105  Utilities->CallLogPop(1101);
6106 }
6107 
6108 // ---------------------------------------------------------------------------
6109 
6110 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6111 {
6112  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6113  TrackElement.PlotVariableTrackElement(7, Disp);
6114  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6115  {
6116  THVPair PosPair;
6117  PosPair.first = TrackElement.HLoc;
6118  PosPair.second = TrackElement.VLoc;
6119  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6120  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6121  {
6122  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6123  }
6124  }
6125  Utilities->CallLogPop(2403);
6126 }
6127 
6128 // ---------------------------------------------------------------------------
6129 
6130 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6131 {
6132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6133  if(TrackElement.TrackType != Points)
6134  {
6135  throw Exception("Error, Wrong track type in PlotPoints");
6136  }
6137  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6138  TrackElement.PlotVariableTrackElement(4, Disp);
6139  if(BothFillets)
6140  {
6141  if(TrackElement.SpeedTag < 28)
6142  {
6143  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6144  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6145  }
6146  else if(TrackElement.SpeedTag < 132)
6147  {
6148  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6149  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6150  }
6151  else
6152  {
6153  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6154  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6155  }
6156  }
6157  else if(!TrackElement.Failed) //not failed
6158  {
6159  if(TrackElement.SpeedTag < 28)
6160  {
6161  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6162  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6163  }
6164  else if(TrackElement.SpeedTag < 132)
6165  {
6166  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6167  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6168  }
6169  else
6170  {
6171  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6172  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6173  }
6174  }
6175  else //failed in fixed position
6176  {
6177  if(TrackElement.SpeedTag < 28)
6178  {
6179  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6180  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6181  }
6182  else if(TrackElement.SpeedTag < 132)
6183  {
6184  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6185  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6186  }
6187  else
6188  {
6189  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6190  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6191  }
6192  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6193  }
6194 // replot platform if required
6195  TIMPair IMPair;
6196  bool FoundFlag;
6197 
6198  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6199  if(FoundFlag)
6200  {
6201  // only one platform possible at points so only need to plot IMPair.first
6202  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6203  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6204  }
6205  Utilities->CallLogPop(519);
6206 }
6207 
6208 // ---------------------------------------------------------------------------
6209 
6210 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6211 {
6212 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6213  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6214  if(TrackElement.TrackType != SignalPost)
6215  {
6216  throw Exception("Error, Wrong track type in PlotSignal");
6217  }
6218  if(!TrackElement.Failed) //added at v2.13.0
6219  {
6220  for(int x = 0; x < 40; x++)
6221  {
6222  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6223  {
6224  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6225  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6226  // in case existing signal is a double yellow
6227  // plot platforms if present
6228  // Graphics::TBitmap* SignalPlatformGraphic;
6229  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6230  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6231  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6232  // to not be plotted with the above function.
6233  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6234  // now plot signal (double yellow overwrites most of signal platform if present)
6235  // additions at version 0.6 for other aspects & ground sigs
6236  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6237  {
6238  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6239  }
6240  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6241  {
6242  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6243  }
6244  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6245  {
6246  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6247  }
6248  else // 4 aspect
6249  {
6250  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6251  }
6252  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6253  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6254  {
6255  if(TrackElement.SpeedTag == 68)
6256  {
6257  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6258  }
6259  if(TrackElement.SpeedTag == 69)
6260  {
6261  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6262  }
6263  if(TrackElement.SpeedTag == 70)
6264  {
6265  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6266  }
6267  if(TrackElement.SpeedTag == 71)
6268  {
6269  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6270  }
6271  if(TrackElement.SpeedTag == 72)
6272  {
6273  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6274  }
6275  if(TrackElement.SpeedTag == 73)
6276  {
6277  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6278  }
6279  if(TrackElement.SpeedTag == 74)
6280  {
6281  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6282  }
6283  if(TrackElement.SpeedTag == 75)
6284  {
6285  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6286  }
6287  }
6288  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6289  // ground signal calling on, need to use normal proceed aspect
6290  {
6291  for(int x = 0; x < 40; x++)
6292  {
6293  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6294  {
6295  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6296  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6297  // plot special signal platform if present
6298  Graphics::TBitmap* SignalPlatformGraphic;
6299  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6300  // now plot signal
6301  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6302  }
6303  }
6304  }
6305  break;
6306  }
6307  }
6308  }
6309  else //failed added at v2.13.0
6310  {
6311  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6312  {
6313  for(int x = 0; x < 8; x++)
6314  {
6315  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6316  {
6317  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6318  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6319  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6320  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6321  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6322  break;
6323  }
6324  }
6325  }
6326  else
6327  {
6328  for(int x = 0; x < 8; x++)
6329  {
6330  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6331  {
6332  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6333  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6334  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6335  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6336  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6337  break;
6338  }
6339  }
6340  }
6341  }
6342  Utilities->CallLogPop(520);
6343 }
6344 
6345 // ---------------------------------------------------------------------------
6346 
6347 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6348 {
6349  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6350  bool FoundFlag;
6351  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6352 
6353  if(!FoundFlag)
6354  {
6355  Utilities->CallLogPop(2112);
6356  return;
6357  }
6358  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6359  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6360 
6361  // don't want 'else if' for the below as may need to plot 2 platforms
6362  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6363  {
6364  if(IAElement1.LocationName == "") // '2' will be same
6365  {
6366  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6367  }
6368  else
6369  {
6370  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6371  }
6372  }
6373  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6374  {
6375  if(IAElement1.LocationName == "") // '2' will be same
6376  {
6377  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6378  }
6379  else
6380  {
6381  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6382  }
6383  }
6384  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6385  {
6386  if(IAElement1.LocationName == "") // '2' will be same
6387  {
6388  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6389  }
6390  else
6391  {
6392  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6393  }
6394  }
6395  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6396  {
6397  if(IAElement1.LocationName == "") // '2' will be same
6398  {
6399  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6400  }
6401  else
6402  {
6403  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6404  }
6405  }
6406  Utilities->CallLogPop(2113);
6407 }
6408 
6409 // ---------------------------------------------------------------------------
6410 
6411 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6412 {
6413 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6415  AnsiString(VLoc));
6416 // find topmost LC, opening them all (to trains) in turn
6417  int UpStep = 0;
6418 
6419  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6420  {
6421  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6422  UpStep--;
6423  }
6424 // now find bottommost LC, opening them all (to trains) in turn
6425  int DownStep = 1;
6426 
6427  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6428  {
6429  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6430  DownStep++;
6431  }
6432 // find leftmost LC, opening them all (to trains) in turn
6433  int LeftStep = 0;
6434 
6435  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6436  {
6437  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6438  LeftStep--;
6439  }
6440 // now find rightmost LC, opening them all (to trains) in turn
6441  int RightStep = 1;
6442 
6443  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6444  {
6445  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6446  RightStep++;
6447  }
6448  Utilities->CallLogPop(1915);
6449 }
6450 
6451 // ---------------------------------------------------------------------------
6452 
6453 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6454 {
6455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6456 // work upwards setting all to manual
6457  int UpStep = -1;
6458 
6459  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6460  {
6461  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6462  UpStep--;
6463  }
6464 // work downwards setting all to manual
6465  int DownStep = 1;
6466 
6467  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6468  {
6469  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6470  DownStep++;
6471  }
6472 // work leftwards setting all to manual
6473  int LeftStep = -1;
6474 
6475  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6476  {
6477  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6478  LeftStep--;
6479  }
6480 // work rightwards setting all to manual
6481  int RightStep = 1;
6482 
6483  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6484  {
6485  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6486  RightStep++;
6487  }
6488  Utilities->CallLogPop(2242);
6489 }
6490 
6491 // ---------------------------------------------------------------------------
6492 
6493 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6494 {
6495  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6496  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6497  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6498  {
6499  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6500  {
6501  BarriersDownVector.at(x).TypeOfRoute = 2;
6502  break;
6503  }
6504  }
6505  Utilities->CallLogPop(2243);
6506 }
6507 
6508 // ---------------------------------------------------------------------------
6509 
6510 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6511 {
6512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6513 // work upwards
6514  int UpStep = 0; //start with this location
6515 
6516  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6517  {
6518  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6519  {
6520  Utilities->CallLogPop(2244);
6521  return(true);
6522  }
6523  UpStep--;
6524  }
6525 // work downwards
6526  int DownStep = 1;
6527 
6528  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6529  {
6530  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6531  {
6532  Utilities->CallLogPop(2245);
6533  return(true);
6534  }
6535  DownStep++;
6536  }
6537 // work leftwards
6538  int LeftStep = -1;
6539 
6540  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6541  {
6542  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6543  {
6544  Utilities->CallLogPop(2246);
6545  return(true);
6546  }
6547  LeftStep--;
6548  }
6549 // work rightwards
6550  int RightStep = 1;
6551 
6552  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6553  {
6554  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6555  {
6556  Utilities->CallLogPop(2247);
6557  return(true);
6558  }
6559  RightStep++;
6560  }
6561  Utilities->CallLogPop(2248);
6562  return(false);
6563 }
6564 
6565 // ---------------------------------------------------------------------------
6566 
6567 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6568 {
6569  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6570  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6571  {
6572  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6573  {
6574  BDVectorPos = x;
6575  Utilities->CallLogPop(2249);
6576  return(true);
6577  }
6578  }
6579  BDVectorPos = -1;
6580  Utilities->CallLogPop(2250);
6581  return(false);
6582 }
6583 
6584 // ---------------------------------------------------------------------------
6585 
6586 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6587 // open to trains
6588 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6589 {
6590  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6591  AnsiString(VLoc));
6592  if(!IsLCAtHV(4, HLoc, VLoc))
6593  {
6594  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6595  }
6596  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6597  {
6598  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6599  }
6600 // check for adjacent LCs & if so open (to trains)
6601  if(BaseElementSpeedTag == 1) // hor track element
6602  {
6603  // find topmost LC, opening them all (to trains) in turn
6604  int UpStep = 0;
6605  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6606  {
6607  UpStep--;
6608  }
6609  UpStep++;
6610  // now find bottommost LC, opening them all (to trains) in turn
6611  int DownStep = 1;
6612  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6613  {
6614  DownStep++;
6615  }
6616  DownStep--;
6617  // now plot graphics, UpStep is smallest & DownStep largest
6618  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6619  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6620  Graphics::TBitmap *RouteGraphic;
6621  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6622  if(TypeOfRoute == 1)
6623  {
6624  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6625  }
6626  else if(TypeOfRoute == 0)
6627  {
6628  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6629  }
6630  else //manual - no route
6631  {
6632  RouteGraphic = BaseGraphic;
6633  }
6634 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6635 // LinkSigRouteGraphicsPtr[1] ver }
6636 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6637 // LinkNonSigRouteGraphicsPtr[1] ver }
6638 
6639  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6640  {
6641  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6642  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6643  if(!Manual)
6644  {
6645  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6646  }
6647  else
6648  {
6649  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6650  }
6651  }
6652  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6653  {
6654  if(UpStep == 0)
6655  {
6656  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6657  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6658  if(!Manual)
6659  {
6660  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6661  }
6662  else
6663  {
6664  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6665  }
6666  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6667  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6668  if(!Manual)
6669  {
6670  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6671  }
6672  else
6673  {
6674  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6675  }
6676  }
6677  else
6678  {
6679  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6680  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6681  if(!Manual)
6682  {
6683  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6684  }
6685  else
6686  {
6687  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6688  }
6689  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6690  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6691  if(!Manual)
6692  {
6693  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6694  }
6695  else
6696  {
6697  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6698  }
6699  }
6700  }
6701  else // at least one plain graphic
6702  {
6703  if(UpStep == 0)
6704  {
6705  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6706  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6707  if(!Manual)
6708  {
6709  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6710  }
6711  else
6712  {
6713  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6714  }
6715  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6716  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6717  if(!Manual)
6718  {
6719  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6720  }
6721  else
6722  {
6723  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6724  }
6725  }
6726  else if(DownStep == 0)
6727  {
6728  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6729  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6730  if(!Manual)
6731  {
6732  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6733  }
6734  else
6735  {
6736  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6737  }
6738  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6739  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6740  if(!Manual)
6741  {
6742  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6743  }
6744  else
6745  {
6746  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6747  }
6748  }
6749  else
6750  {
6751  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6752  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6753  if(!Manual)
6754  {
6755  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6756  }
6757  else
6758  {
6759  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6760  }
6761  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6762  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6763  if(!Manual)
6764  {
6765  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6766  }
6767  else
6768  {
6769  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6770  }
6771  }
6772  for(int x = (UpStep + 1); x < DownStep; x++)
6773  {
6774  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6775  if(x == 0)
6776  {
6777  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6778  }
6779  else
6780  {
6781  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6782  }
6783  if(!Manual)
6784  {
6785  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6786  }
6787  else
6788  {
6789  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6790  }
6791  }
6792  }
6793  Disp->Update();
6794  Utilities->CallLogPop(1958);
6795  return;
6796  }
6797 
6798  else // ver track element
6799  {
6800  // find leftmost LC, opening them all (to trains) in turn
6801  int LStep = 0;
6802  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6803  {
6804  LStep--;
6805  }
6806  LStep++;
6807  // now find rightmost LC, opening them all (to trains) in turn
6808  int RStep = 1;
6809  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6810  {
6811  RStep++;
6812  }
6813  RStep--;
6814  // now plot graphics, LStep is smallest & RStep largest
6815  Graphics::TBitmap *RouteGraphic;
6816  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6817  if(TypeOfRoute == 1)
6818  {
6819  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6820  }
6821  else if(TypeOfRoute == 0)
6822  {
6823  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6824  }
6825  else //manual
6826  {
6827  RouteGraphic = BaseGraphic;
6828  }
6829 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6830 // LinkSigRouteGraphicsPtr[1] ver }
6831 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6832 // LinkNonSigRouteGraphicsPtr[1] ver }
6833  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6834  {
6835  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6836  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6837  if(!Manual)
6838  {
6839  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6840  }
6841  else
6842  {
6843  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6844  }
6845  }
6846  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6847  {
6848  if(LStep == 0)
6849  {
6850  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6851  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6852  if(!Manual)
6853  {
6854  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6855  }
6856  else
6857  {
6858  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6859  }
6860  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6861  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6862  if(!Manual)
6863  {
6864  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6865  }
6866  else
6867  {
6868  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6869  }
6870  }
6871  else
6872  {
6873  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6874  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6875  if(!Manual)
6876  {
6877  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6878  }
6879  else
6880  {
6881  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6882  }
6883  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6884  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6885  if(!Manual)
6886  {
6887  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6888  }
6889  else
6890  {
6891  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6892  }
6893  }
6894  }
6895  else // at least one plain graphic
6896  {
6897  if(LStep == 0)
6898  {
6899  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6900  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6901  if(!Manual)
6902  {
6903  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6904  }
6905  else
6906  {
6907  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6908  }
6909  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6910  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6911  if(!Manual)
6912  {
6913  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6914  }
6915  else
6916  {
6917  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6918  }
6919  }
6920  else if(RStep == 0)
6921  {
6922  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6923  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6924  if(!Manual)
6925  {
6926  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6927  }
6928  else
6929  {
6930  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6931  }
6932  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6933  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6934  if(!Manual)
6935  {
6936  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6937  }
6938  else
6939  {
6940  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6941  }
6942  }
6943  else
6944  {
6945  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6946  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6947  if(!Manual)
6948  {
6949  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6950  }
6951  else
6952  {
6953  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6954  }
6955  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6956  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6957  if(!Manual)
6958  {
6959  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6960  }
6961  else
6962  {
6963  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6964  }
6965  }
6966  for(int x = (LStep + 1); x < RStep; x++)
6967  {
6968  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6969  if(x == 0)
6970  {
6971  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6972  }
6973  else
6974  {
6975  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6976  }
6977  if(!Manual)
6978  {
6979  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6980  }
6981  else
6982  {
6983  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6984  }
6985  }
6986  }
6987  Disp->Update();
6988  Utilities->CallLogPop(1896);
6989  return;
6990  }
6991 }
6992 
6993 // ---------------------------------------------------------------------------
6994 
6995 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6996 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6997 {
6998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6999  AnsiString(HLoc) + "," + AnsiString(VLoc));
7000  if(!IsLCAtHV(29, HLoc, VLoc))
7001  {
7002  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7003  }
7004  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7005  {
7006  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7007  }
7008 // check for adjacent LCs & if so open (to trains)
7009  if(BaseElementSpeedTag == 1) // hor track element
7010  {
7011  // find topmost LC, opening them all (to trains) in turn
7012  int UpStep = 0;
7013  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7014  {
7015  UpStep--;
7016  }
7017  UpStep++;
7018  // now find bottommost LC, opening them all (to trains) in turn
7019  int DownStep = 1;
7020  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7021  {
7022  DownStep++;
7023  }
7024  DownStep--;
7025  // now plot graphics, UpStep is smallest & DownStep largest
7026  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7027  {
7028  if(!Manual)
7029  {
7030  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7031  }
7032  else
7033  {
7034  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7035  }
7036  }
7037  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7038  {
7039  if(!Manual)
7040  {
7041  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7042  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7043  }
7044  else
7045  {
7046  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7047  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7048  }
7049  }
7050  else // at least one plain graphic
7051  {
7052  if(!Manual)
7053  {
7054  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7055  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7056  for(int x = (UpStep + 1); x < DownStep; x++)
7057  {
7058  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7059  }
7060  }
7061  else
7062  {
7063  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7064  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7065  for(int x = (UpStep + 1); x < DownStep; x++)
7066  {
7067  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7068  }
7069  }
7070  }
7071  // set markers
7072  for(int x = UpStep; x <= DownStep; x++)
7073  {
7074  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7075  }
7076  Display->Update();
7077  Utilities->CallLogPop(1944);
7078  return;
7079  }
7080 
7081  else // ver track element
7082  {
7083  // find leftmost LC, opening them all (to trains) in turn
7084  int LStep = 0;
7085  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7086  {
7087  LStep--;
7088  }
7089  LStep++;
7090  // now find rightmost LC, opening them all (to trains) in turn
7091  int RStep = 1;
7092  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7093  {
7094  RStep++;
7095  }
7096  RStep--;
7097  // now plot graphics, LStep is smallest & RStep largest
7098  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7099  {
7100  if(!Manual)
7101  {
7102  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7103  }
7104  else
7105  {
7106  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7107  }
7108  }
7109  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7110  {
7111  if(!Manual)
7112  {
7113  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7114  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7115  }
7116  else
7117  {
7118  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7119  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7120  }
7121  }
7122  else // at least one plain graphic
7123  {
7124  if(!Manual)
7125  {
7126  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7127  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7128  for(int x = (LStep + 1); x < RStep; x++)
7129  {
7130  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7131  }
7132  }
7133  else
7134  {
7135  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7136  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7137  for(int x = (LStep + 1); x < RStep; x++)
7138  {
7139  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7140  }
7141  }
7142  }
7143  // set markers
7144  for(int x = LStep; x <= RStep; x++)
7145  {
7146  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7147  }
7148  Disp->Update();
7149  Utilities->CallLogPop(1945);
7150  return;
7151  }
7152 }
7153 
7154 // ---------------------------------------------------------------------------
7155 
7156 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7157 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7158 {
7159  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7160  AnsiString(VLoc));
7161  if(!IsLCAtHV(9, HLoc, VLoc))
7162  {
7163  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7164  }
7165  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7166  {
7167  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7168  }
7169 // check for adjacent LCs & if so close (to trains)
7170  if(BaseElementSpeedTag == 1) // hor track element
7171  {
7172  // find topmost LC, closing them all (to trains) in turn
7173  int UpStep = 0;
7174  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7175  {
7176  UpStep--;
7177  }
7178  UpStep++;
7179  // now find bottommost LC, opening them all (to trains) in turn
7180  int DownStep = 1;
7181  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7182  {
7183  DownStep++;
7184  }
7185  DownStep--;
7186  // now plot graphics, UpStep is smallest & DownStep largest
7187  for(int x = UpStep; x < (DownStep + 1); x++)
7188  {
7189  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7190  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7191  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7192  }
7193  Disp->Update();
7194  Utilities->CallLogPop(1959);
7195  return;
7196  }
7197 
7198  else // ver track element
7199  {
7200  // find leftmost LC, closing them all (to trains) in turn
7201  int LStep = 0;
7202  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7203  {
7204  LStep--;
7205  }
7206  LStep++;
7207  // now find rightmost LC, opening them all (to trains) in turn
7208  int RStep = 1;
7209  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7210  {
7211  RStep++;
7212  }
7213  RStep--;
7214  // now plot graphics, LStep is smallest & RStep largest
7215  for(int x = LStep; x < (RStep + 1); x++)
7216  {
7217  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7218  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7219  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7220  }
7221  Disp->Update();
7222  Utilities->CallLogPop(1960);
7223  return;
7224  }
7225 }
7226 
7227 // ---------------------------------------------------------------------------
7228 
7229 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7230 // closed to trains
7231 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7232 {
7233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7234  AnsiString(HLoc) + "," + AnsiString(VLoc));
7235  if(!IsLCAtHV(34, HLoc, VLoc))
7236  {
7237  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7238  }
7239  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7240  {
7241  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7242  }
7243  TTrackElement TE;
7244 
7245 // check for adjacent LCs & if so close (to trains)
7246  if(BaseElementSpeedTag == 1) // hor track element
7247  {
7248  // find topmost LC, closing them all (to trains) in turn
7249  int UpStep = 0;
7250  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7251  {
7252  UpStep--;
7253  }
7254  UpStep++;
7255  // now find bottommost LC, opening them all (to trains) in turn
7256  int DownStep = 1;
7257  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7258  {
7259  DownStep++;
7260  }
7261  DownStep--;
7262  // now plot graphics, UpStep is smallest & DownStep largest
7263  for(int x = UpStep; x <= DownStep; x++)
7264  {
7265  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7266  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7267  }
7268  Display->Update();
7269  Utilities->CallLogPop(1946);
7270  return;
7271  }
7272 
7273  else // ver track element
7274  {
7275  // find leftmost LC, closing them all (to trains) in turn
7276  int LStep = 0;
7277  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7278  {
7279  LStep--;
7280  }
7281  LStep++;
7282  // now find rightmost LC, opening them all (to trains) in turn
7283  int RStep = 1;
7284  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7285  {
7286  RStep++;
7287  }
7288  RStep--;
7289  // now plot graphics, LStep is smallest & RStep largest
7290  for(int x = LStep; x <= RStep; x++)
7291  {
7292  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7293  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7294  }
7295  Display->Update();
7296  Utilities->CallLogPop(1947);
7297  return;
7298  }
7299 }
7300 
7301 // ---------------------------------------------------------------------------
7302 
7303 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7304 {
7305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7306  Graphics::TBitmap *RouteGraphic;
7307  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7308 
7309  if(BaseElementSpeedTag == 1)
7310  {
7311  if(TypeOfRoute == 1)
7312  {
7313  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7314  }
7315  else if(TypeOfRoute == 0)
7316  {
7317  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7318  }
7319  else //manual
7320  {
7321  RouteGraphic = BaseGraphic;
7322  }
7323  if(State == Raising)
7324  {
7325  RouteGraphic = BaseGraphic;
7326  }
7327  }
7328  else
7329  {
7330  BaseGraphic = RailGraphics->gl2;
7331  if(TypeOfRoute == 1)
7332  {
7333  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7334  }
7335  else if(TypeOfRoute == 0)
7336  {
7337  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7338  }
7339  else
7340  {
7341  RouteGraphic = BaseGraphic; //manual
7342  }
7343  if(State == Raising)
7344  {
7345  RouteGraphic = BaseGraphic;
7346  }
7347  }
7348  int UpStep = 0;
7349 
7350  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7351  {
7352  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7353  if(UpStep == 0)
7354  {
7355  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7356  }
7357  else
7358  {
7359  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7360  }
7361  UpStep--;
7362  }
7363 // now find bottommost LC, opening them all (to trains) in turn
7364  int DownStep = 1;
7365 
7366  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7367  {
7368  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7369  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7370  DownStep++;
7371  }
7372  int LeftStep = 0;
7373 
7374  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7375  {
7376  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7377  if(LeftStep == 0)
7378  {
7379  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7380  }
7381  else
7382  {
7383  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7384  }
7385  LeftStep--;
7386  }
7387 // now find rightmost LC, opening them all (to trains) in turn
7388  int RightStep = 1;
7389 
7390  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7391  {
7392  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7393  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7394  RightStep++;
7395  }
7396  Disp->Update();
7397  Utilities->CallLogPop(1914);
7398 }
7399 
7400 // ---------------------------------------------------------------------------
7401 
7402 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7403 {
7404 // return false for no LC there, flashing or a closed (to trains) LC
7405  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7406  bool FoundFlag;
7407  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7408 
7409  if(!FoundFlag)
7410  {
7411  Utilities->CallLogPop(1898);
7412  return(false);
7413  }
7414  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7415  {
7416  Utilities->CallLogPop(1899);
7417  return(false);
7418  }
7419  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7420  {
7421  Utilities->CallLogPop(1900);
7422  return(true);
7423  }
7424  Utilities->CallLogPop(1901);
7425  return(false);
7426 }
7427 
7428 // ---------------------------------------------------------------------------
7429 
7430 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7431 {
7432 // return false for no LC there, flashing LC or open (to trains) LC
7433  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7434  bool FoundFlag;
7435  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7436 
7437  if(!FoundFlag)
7438  {
7439  Utilities->CallLogPop(1922);
7440  return(false);
7441  }
7442  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7443  {
7444  Utilities->CallLogPop(1923);
7445  return(false);
7446  }
7447  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7448  {
7449  Utilities->CallLogPop(1924);
7450  return(true);
7451  }
7452  Utilities->CallLogPop(1925);
7453  return(false);
7454 }
7455 
7456 // ---------------------------------------------------------------------------
7457 
7458 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7459 {
7460 // return true for barrier in process of moving
7461  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7462  bool FoundFlag;
7463  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7464 
7465  if(!FoundFlag)
7466  {
7467  Utilities->CallLogPop(1918);
7468  return(false);
7469  }
7470  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7471  {
7472  Utilities->CallLogPop(1919);
7473  return(false);
7474  }
7475  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7476  {
7477  Utilities->CallLogPop(1920);
7478  return(true);
7479  }
7480  Utilities->CallLogPop(1921);
7481  return(false);
7482 }
7483 
7484 // ---------------------------------------------------------------------------
7485 
7486 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7487 {
7488 // return true for an LC at H&V
7489  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7490  bool FoundFlag;
7491  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7492 
7493  if(!FoundFlag)
7494  {
7495  Utilities->CallLogPop(1902);
7496  return(false);
7497  }
7498  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7499  {
7500  Utilities->CallLogPop(1903);
7501  return(false);
7502  }
7503  Utilities->CallLogPop(1904);
7504  return(true);
7505 }
7506 
7507 // ---------------------------------------------------------------------------
7508 
7509 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7510 {
7511  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7512  AnsiString(Attr));
7513  bool FoundFlag;
7514  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7515 
7516  if(!FoundFlag)
7517  {
7518  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7519  }
7520  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7521  {
7522  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7523  }
7524  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7525  Utilities->CallLogPop(1905);
7526  return;
7527 }
7528 
7529 // ---------------------------------------------------------------------------
7530 
7532 {
7533  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7534  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7535  {
7536  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7537  if(InactiveTrackElement.TrackType == LevelCrossing)
7538  {
7539  InactiveTrackElementAt(141, x).Attribute = 0;
7540  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7541  }
7542  }
7543  Utilities->CallLogPop(1913);
7544  return;
7545 }
7546 
7547 // ---------------------------------------------------------------------------
7548 
7549 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7550 {
7551 // return true if there is either a route set or being set on any element or a train on any element
7552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7553  "," + AnsiString(VLoc));
7554 
7555  THVPair TrackMapKeyPair;
7556  TTrack::TTrackMapIterator TrackMapPtr;
7557  int DummyRouteNumber;
7558 
7559  TrainPresent = false;
7560 // find topmost LC, checking each for routes & trains
7561  int UpStep = 0;
7562 
7563  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7564  {
7565  TrackMapKeyPair.first = HLoc;
7566  TrackMapKeyPair.second = VLoc + UpStep;
7567  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7568  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7569  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7570  {
7571  Utilities->CallLogPop(1932);
7572  return(true);
7573  }
7574  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7575  {
7576  TrainPresent = true;
7577  Utilities->CallLogPop(1933);
7578  return(true);
7579  }
7580  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7581  {
7582  Utilities->CallLogPop(2274);
7583  return(true);
7584  }
7585  UpStep--;
7586  }
7587 // now find bottommost LC, opening them all (to trains) in turn
7588  int DownStep = 1;
7589 
7590  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7591  {
7592  TrackMapKeyPair.first = HLoc;
7593  TrackMapKeyPair.second = VLoc + DownStep;
7594  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7595  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7596  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7597  {
7598  Utilities->CallLogPop(1934);
7599  return(true);
7600  }
7601  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7602  {
7603  TrainPresent = true;
7604  Utilities->CallLogPop(1935);
7605  return(true);
7606  }
7607  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7608  {
7609  Utilities->CallLogPop(2275);
7610  return(true);
7611  }
7612  DownStep++;
7613  }
7614 // find leftmost LC
7615  int LeftStep = 0;
7616 
7617  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7618  {
7619  TrackMapKeyPair.first = HLoc + LeftStep;
7620  TrackMapKeyPair.second = VLoc;
7621  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7622  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7623  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7624  {
7625  Utilities->CallLogPop(1936);
7626  return(true);
7627  }
7628  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7629  {
7630  TrainPresent = true;
7631  Utilities->CallLogPop(1937);
7632  return(true);
7633  }
7634  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7635  {
7636  Utilities->CallLogPop(2276);
7637  return(true);
7638  }
7639  LeftStep--;
7640  }
7641 // now find rightmost LC, opening them all (to trains) in turn
7642  int RightStep = 1;
7643 
7644  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7645  {
7646  TrackMapKeyPair.first = HLoc + RightStep;
7647  TrackMapKeyPair.second = VLoc;
7648  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7649  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7650  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7651  {
7652  Utilities->CallLogPop(1938);
7653  return(true);
7654  }
7655  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7656  {
7657  TrainPresent = true;
7658  Utilities->CallLogPop(1939);
7659  return(true);
7660  }
7661  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7662  {
7663  Utilities->CallLogPop(2277);
7664  return(true);
7665  }
7666  RightStep++;
7667  }
7668  Utilities->CallLogPop(1940);
7669  return(false);
7670 }
7671 
7672 // ---------------------------------------------------------------------------
7673 
7674 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7675 {
7676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7677  for(unsigned int x = 0; x < SearchVector.size(); x++)
7678  {
7679  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7680  {
7681  Utilities->CallLogPop(2278);
7682  return(true);
7683  }
7684  }
7685  Utilities->CallLogPop(2279);
7686  return(false);
7687 }
7688 
7689 // ---------------------------------------------------------------------------
7690 
7691 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7692 {
7693  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7694  AnsiString(HLoc) + "," + AnsiString(VLoc));
7695  if(!IsLCAtHV(60, HLoc, VLoc))
7696  {
7697  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7698  }
7699 
7700 // check for adjacent LCs
7701  // find topmost LC
7702  int UpStep = 0;
7703  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7704  {
7705  UpStep--;
7706  }
7707  UpStep++;
7708  // now find bottommost LC, opening them all (to trains) in turn
7709  int DownStep = 1;
7710  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7711  {
7712  DownStep++;
7713  }
7714  DownStep--;
7715  // now plot graphics, UpStep is smallest & DownStep largest
7716  for(int x = UpStep; x <= DownStep; x++)
7717  {
7718  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7719  }
7720 
7721  // find leftmost LC, closing them all (to trains) in turn
7722  int LStep = 0;
7723  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7724  {
7725  LStep--;
7726  }
7727  LStep++;
7728  // now find rightmost LC, opening them all (to trains) in turn
7729  int RStep = 1;
7730  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7731  {
7732  RStep++;
7733  }
7734  RStep--;
7735  // now plot graphics, LStep is smallest & RStep largest
7736  for(int x = LStep; x <= RStep; x++)
7737  {
7738  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7739  }
7740  Display->Update();
7741  Utilities->CallLogPop(2315);
7742  return;
7743 }
7744 
7745 // ---------------------------------------------------------------------------
7746 
7747 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7748 {
7749  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7750  if(TrackElement.TrackType != Points)
7751  {
7752  throw Exception("Error, Wrong track type in GetFilletGraphic");
7753  }
7754  if(TrackElement.SpeedTag < 28)
7755  {
7756  Utilities->CallLogPop(521);
7757  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7758  }
7759  else if(TrackElement.SpeedTag < 132)
7760  {
7761  Utilities->CallLogPop(522);
7762 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7763  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7764  }
7765  else
7766  {
7767  Utilities->CallLogPop(1537);
7768  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7769  }
7770 }
7771 
7772 // ---------------------------------------------------------------------------
7773 
7775 {
7776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7777  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7778  {
7779  TrackElementAt(1351, x).TrainIDOnElement = -1;
7782  }
7783  Utilities->CallLogPop(1342);
7784 }
7785 
7786 // ---------------------------------------------------------------------------
7787 
7788 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7789 /*
7790  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7791 */
7792 {
7793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7794  AnsiString(ScreenPosV));
7795  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7796  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7797 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7798  Utilities->CallLogPop(535);
7799 }
7800 
7801 // ---------------------------------------------------------------------------
7802 
7803 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7804 /*
7805  Converts the screen position to the true (without offsets) position
7806 */
7807 {
7808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7809  AnsiString(ScreenPosV));
7810  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7811  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7812  Utilities->CallLogPop(536);
7813 }
7814 
7815 // ---------------------------------------------------------------------------
7816 
7817 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7818 {
7819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7820  AnsiString(VPosTrue));
7821  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7822  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7823  Utilities->CallLogPop(537);
7824 }
7825 
7826 // ---------------------------------------------------------------------------
7827 
7828 void TTrack::CheckMapAndTrack(int Caller) // test
7829 {
7830  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7831  int Zeroes = 0;
7832  bool FoundFlag;
7833 
7834  for(unsigned int a = 0; a < TrackVector.size(); a++)
7835  {
7836  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7837  if(CheckElement.SpeedTag == 0)
7838  {
7839  Zeroes++; // zeroed elements not saved in map
7840  }
7841  else
7842  {
7843  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7844  if(!FoundFlag)
7845  {
7846  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7847  " in TrackMap, Caller=" + (AnsiString)Caller);
7848  }
7849  if(MapVecPos != (int)a)
7850  {
7851  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7852  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7853  (AnsiString)Caller);
7854  }
7855  }
7856  }
7857  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7858  {
7859  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7860  " Caller=" + (AnsiString)Caller);
7861  }
7862  Utilities->CallLogPop(538);
7863  return;
7864 }
7865 
7866 // ---------------------------------------------------------------------------
7867 
7868 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7869 {
7870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7871  bool FoundFlag;
7872  TIMPair InactivePair;
7873 
7874  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7875  {
7876  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7877  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7878  if(!FoundFlag)
7879  {
7880  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7881  " in InactiveMap, Caller=" + (AnsiString)Caller);
7882  }
7883  if((InactivePair.first != a) && (InactivePair.second != a))
7884  {
7885  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7886  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7887  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7888  }
7889  }
7890  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7891  {
7892  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7893  " Caller=" + (AnsiString)Caller);
7894  }
7895  Utilities->CallLogPop(539);
7896 }
7897 
7898 // ---------------------------------------------------------------------------
7899 
7900 void TTrack::CheckGapMap(int Caller) // test
7901 {
7902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7903  int Position1, Position2;
7904  TTrackElement TrackElement1, TrackElement2;
7905  TGapMapIterator GapMapPtr;
7906 
7907  if(!GapMap.empty())
7908  {
7909  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7910  {
7911  int HLoc1 = GapMapPtr->first.first;
7912  int VLoc1 = GapMapPtr->first.second;
7913  int HLoc2 = GapMapPtr->second.first;
7914  int VLoc2 = GapMapPtr->second.second;
7915  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7916  {
7917  throw Exception("Failed to find H & V for gap1, GapMap in error");
7918  }
7919  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7920  {
7921  throw Exception("Failed to find H & V for gap2, GapMap in error");
7922  }
7923  if(TrackElementAt(17, Position1).TrackType != GapJump)
7924  {
7925  throw Exception("Element at Pos1 not a gap, GapMap in error");
7926  }
7927  if(TrackElementAt(18, Position2).TrackType != GapJump)
7928  {
7929  throw Exception("Element at Pos2 not a gap, GapMap in error");
7930  }
7931  }
7932  }
7933  unsigned int GapCount = 0;
7934 
7935  for(unsigned int a = 0; a < TrackVector.size(); a++)
7936  {
7937  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7938  if(CheckElement.TrackType == GapJump)
7939  {
7940  GapCount++;
7941  }
7942  }
7943  if((GapMap.size() * 2) != GapCount)
7944  {
7945  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7946  (AnsiString)Caller);
7947  }
7948  Utilities->CallLogPop(540);
7949 }
7950 
7951 // ---------------------------------------------------------------------------
7952 
7953 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7954 {
7955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7956  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7957  {
7958  if(TrackFinished)
7959  {
7960  throw Exception("Error - TrackFinished with erase element still present");
7961  }
7962  Utilities->CallLogPop(541);
7963  return; // erased element, can't set ID
7964  }
7965  AnsiString IDString;
7966 
7967  if(TrackElement.HLoc < 0)
7968  {
7969  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7970  }
7971  else
7972  {
7973  IDString = AnsiString(TrackElement.HLoc) + "-";
7974  }
7975  if(TrackElement.VLoc < 0)
7976  {
7977  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7978  }
7979  else
7980  {
7981  IDString += AnsiString(TrackElement.VLoc);
7982  }
7983  TrackElement.ElementID = IDString;
7984  Utilities->CallLogPop(542);
7985 }
7986 
7987 // ---------------------------------------------------------------------------
7988 
7989 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7990 {
7991 // e.g. "8-13", "00008-13", "N43-N127", etc
7992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
7993  int DelimPos;
7994 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
7995  {
7996  for(int x = 1; x < String.Length() + 1; x++)
7997  {
7998  if(String.IsDelimiter("-", x))
7999  {
8000  DelimPos = x;
8001  break;
8002  }
8003  if(x == String.Length())
8004  {
8005  if(GiveMessages)
8006  {
8007  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8008  }
8009  Utilities->CallLogPop(543);
8010  return(-1);
8011  }
8012  }
8013  if(DelimPos == 1)
8014  {
8015  if(GiveMessages)
8016  {
8017  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8018  }
8019  Utilities->CallLogPop(544);
8020  return(-1);
8021  }
8022  if(DelimPos == String.Length())
8023  {
8024  if(GiveMessages)
8025  {
8026  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8027  }
8028  Utilities->CallLogPop(545);
8029  return(-1);
8030  }
8031  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8032  {
8033  if(GiveMessages)
8034  {
8035  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8036  }
8037  Utilities->CallLogPop(1508);
8038  return(-1);
8039  }
8040  int HLoc, VLoc;
8041 
8042  if(String.SubString(1, 1) != "N")
8043  {
8044  for(int x = 1; x < DelimPos; x++)
8045  {
8046  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8047  {
8048  if(GiveMessages)
8049  {
8050  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8051  }
8052  Utilities->CallLogPop(546);
8053  return(-1);
8054  }
8055  }
8056  }
8057  if(String.SubString(1, 1) == "N")
8058  {
8059  for(int x = 2; x < DelimPos; x++)
8060  {
8061  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8062  {
8063  if(GiveMessages)
8064  {
8065  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8066  }
8067  Utilities->CallLogPop(763);
8068  return(-1);
8069  }
8070  }
8071  }
8072  if(String.SubString(1, 1) == "N")
8073  {
8074  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8075  }
8076  else
8077  {
8078  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8079  }
8080  if(String.SubString(DelimPos + 1, 1) != "N")
8081  {
8082  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8083  {
8084  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8085  {
8086  if(GiveMessages)
8087  {
8088  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8089  }
8090  Utilities->CallLogPop(547);
8091  return(-1);
8092  }
8093  }
8094  }
8095  if(String.SubString(DelimPos + 1, 1) == "N")
8096  {
8097  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8098  {
8099  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8100  {
8101  if(GiveMessages)
8102  {
8103  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8104  }
8105  Utilities->CallLogPop(764);
8106  return(-1);
8107  }
8108  }
8109  }
8110  if(String.SubString(DelimPos + 1, 1) == "N")
8111  {
8112  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8113  }
8114  else
8115  {
8116  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8117  }
8118  THVPair HVPair(HLoc, VLoc);
8119  TTrackMapIterator TrackMapPtr;
8120 
8121  TrackMapPtr = TrackMap.find(HVPair);
8122  if(TrackMapPtr == TrackMap.end())
8123  {
8124  if(GiveMessages)
8125  {
8126  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8127  }
8128  Utilities->CallLogPop(548);
8129  return(-1);
8130  }
8131  Utilities->CallLogPop(549);
8132  return(TrackMapPtr->second);
8133  }
8134  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8135  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8136  {
8137  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8138  Utilities->CallLogPop(2481);
8139  return(-1);
8140  }
8141 }
8142 
8143 // ---------------------------------------------------------------------------
8144 
8145 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8146 /*
8147  True for linked properly at both ends
8148 */
8149 {
8150  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8151  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8152  int HLoc = TrackElement.HLoc;
8153  int VLoc = TrackElement.VLoc;
8154 
8155  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8156  {
8157  Utilities->CallLogPop(1821);
8158  return(false);
8159  }
8160  if(TrackElement.SpeedTag == 129) // vertical footbridge
8161  {
8162  // check top connection
8163  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8164  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8165  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8166  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8167  {
8168  Utilities->CallLogPop(550);
8169  return(false);
8170  }
8171  // check bottom connection
8172  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8173  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8174  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8175  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8176  {
8177  Utilities->CallLogPop(551);
8178  return(false);
8179  }
8180  }
8181  if(TrackElement.SpeedTag == 145) // vertical underpass
8182  {
8183  // check top connection
8184  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8185  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8186  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8187  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8188  {
8189  Utilities->CallLogPop(2114);
8190  return(false);
8191  }
8192  // check bottom connection
8193  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8194  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8195  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8196  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8197  {
8198  Utilities->CallLogPop(2115);
8199  return(false);
8200  }
8201  }
8202  if(TrackElement.SpeedTag == 130) // hor footbridge
8203  {
8204  // check left connection
8205  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8206  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8207  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8208  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8209  {
8210  Utilities->CallLogPop(552);
8211  return(false);
8212  }
8213  // check right connection
8214  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8215  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8216  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8217  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8218  {
8219  Utilities->CallLogPop(553);
8220  return(false);
8221  }
8222  }
8223  if(TrackElement.SpeedTag == 146) // hor u'pass
8224  {
8225  // check left connection
8226  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8227  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8228  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8229  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8230  {
8231  Utilities->CallLogPop(2116);
8232  return(false);
8233  }
8234  // check right connection
8235  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8236  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8237  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8238  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8239  {
8240  Utilities->CallLogPop(2117);
8241  return(false);
8242  }
8243  }
8244  Utilities->CallLogPop(554);
8245  return(true);
8246 }
8247 
8248 // ---------------------------------------------------------------------------
8249 
8250 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8251 /*
8252  return true if the SpeedTag present in the map at H & V
8253 */
8254 {
8255  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8256  AnsiString(SpeedTag));
8257  if(InactiveTrack2MultiMap.empty())
8258  {
8259  Utilities->CallLogPop(555);
8260  return(false);
8261  }
8262  THVPair HVPair(HLoc, VLoc);
8264  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8265  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8266 
8267  if(HVRange.first == HVRange.second)
8268  {
8269  Utilities->CallLogPop(556);
8270  return(false);
8271  }
8272  else
8273  {
8274  HVIt1 = HVRange.first;
8275  }
8276  TTrackElement Temp1, Temp2; // test
8277 
8278  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8279  if(--HVRange.second != HVRange.first)
8280  {
8281  HVIt2 = HVRange.second;
8282  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8283  }
8284  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8285  HVIt2->second).SpeedTag == SpeedTag)))
8286  {
8287  Utilities->CallLogPop(557);
8288  return(true);
8289  }
8290  else
8291  {
8292  Utilities->CallLogPop(558);
8293  return(false);
8294  }
8295 }
8296 
8297 // ---------------------------------------------------------------------------
8298 
8299 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8300 /*
8301  return true if the SpeedTag present in the map at H & V
8302 */
8303 {
8304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8305  AnsiString(SpeedTag));
8306  if(TrackMap.empty())
8307  {
8308  Utilities->CallLogPop(559);
8309  return(false);
8310  }
8311  THVPair HVPair(HLoc, VLoc);
8312  TTrackMapIterator End = TrackMap.end();
8313  TTrackMapIterator It = End;
8314 
8315  It = TrackMap.find(HVPair);
8316  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8317  {
8318  Utilities->CallLogPop(560);
8319  return(true);
8320  }
8321  else
8322  {
8323  Utilities->CallLogPop(561);
8324  return(false);
8325  }
8326 }
8327 
8328 // ---------------------------------------------------------------------------
8329 
8330 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8331 {
8332 /*
8333  General:
8334  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8335  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8336  a NamedNonStationLocation.
8337  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8338  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8339  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8340  platform at that location).
8341 
8342  Linked named location elements are those explained in TTrack::TTrack()
8343 
8344  Detail:
8345  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8346  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8347  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8348  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8349  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8350  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8351 
8352  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8353  this function a single element should be in the List (normally from the user's selection but can also be from
8354  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8355  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8356  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8357  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8358  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8359  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8360  moves them into the Map. At the end all linked elements are in the Map.
8361 
8362  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8363  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8364  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8365 */
8366 
8367 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8368 // Display->FileDiagnostics(TestString);//test
8369 
8370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8371  AnsiString TestString1, TestString2; // test
8372 
8373  Track->LNDone2MultiMap.clear();
8374  if(LNPendingList.size() != 1)
8375  {
8376  throw Exception("LNPendingList size not 1 on entry");
8377  }
8378  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8379  while(!LNPendingList.empty())
8380  {
8381  CurrentElementNumber = LNPendingList.front();
8382  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8383  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8384  int H = CurrentElement->HLoc;
8385  int V = CurrentElement->VLoc;
8386  int Tag = CurrentElement->SpeedTag;
8387  if(Tag == 76) // top plat
8388  {
8389  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8390  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8391  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8392  for(int x = 0; x < 25; x++)
8393  {
8394  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8395  {
8396  LNPendingList.insert(LNPendingList.end(), NewElement);
8397  }
8398  }
8399  }
8400  else if(Tag == 77) // bot plat
8401  {
8402  for(int x = 0; x < 25; x++)
8403  {
8404  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8405  {
8406  LNPendingList.insert(LNPendingList.end(), NewElement);
8407  }
8408  }
8409  }
8410  else if(Tag == 78) // l plat
8411  {
8412  for(int x = 0; x < 25; x++)
8413  {
8414  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8415  {
8416  LNPendingList.insert(LNPendingList.end(), NewElement);
8417  }
8418  }
8419  }
8420  else if(Tag == 79) // r plat
8421  {
8422  for(int x = 0; x < 25; x++)
8423  {
8424  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8425  {
8426  LNPendingList.insert(LNPendingList.end(), NewElement);
8427  }
8428  }
8429  }
8430  else if(Tag == 96) // conc
8431  {
8432  for(int x = 0; x < 28; x++)
8433  {
8434  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8435  {
8436  LNPendingList.insert(LNPendingList.end(), NewElement);
8437  }
8438  }
8439  }
8440  else if(Tag == 129) // vert footbridge
8441  {
8442  for(int x = 0; x < 8; x++)
8443  {
8444  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8445  {
8446  LNPendingList.insert(LNPendingList.end(), NewElement);
8447  }
8448  }
8449  }
8450  else if(Tag == 130) // hor footbridge
8451  {
8452  for(int x = 0; x < 8; x++)
8453  {
8454  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8455  {
8456  LNPendingList.insert(LNPendingList.end(), NewElement);
8457  }
8458  }
8459  }
8460  else if(Tag == 131) // named location
8461  {
8462  for(int x = 0; x < 4; x++)
8463  {
8464  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8465  {
8466  LNPendingList.insert(LNPendingList.end(), NewElement);
8467  }
8468  }
8469  }
8470  else if(Tag == 145) // v u'pass
8471  {
8472  for(int x = 0; x < 8; x++)
8473  {
8474  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8475  {
8476  LNPendingList.insert(LNPendingList.end(), NewElement);
8477  }
8478  }
8479  }
8480  else if(Tag == 146) // h u'pass
8481  {
8482  for(int x = 0; x < 8; x++)
8483  {
8484  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8485  {
8486  LNPendingList.insert(LNPendingList.end(), NewElement);
8487  }
8488  }
8489  }
8490  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8491 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8492  if(AddingElements)
8493  {
8494  int HPos, VPos; // not used but needed for FindText function
8495  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8496  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8497  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8498  {
8499  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8500  if((ExistingName != "") && (ExistingName != LocationName))
8501  {
8502  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8503  {
8504  } // name not in LocationNameMultiMap, so don't erase from TextVector
8505  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8506  {
8507  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8508  {
8509  ;
8510  } // condition not used
8511 
8512  }
8513  }
8514  }
8515  }
8516  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8517  // track at that loc
8518  THVPair HVPair(H, V);
8519  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8520  LNDone2MultiMapEntry.first = HVPair;
8521  LNDone2MultiMapEntry.second = LNPendingList.front();
8522  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8523  LNPendingList.erase(LNPendingList.begin());
8524  }
8525 
8526 // search all name multimap for same name where corresponding active elements don't appear in
8527 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8528 
8529  TLocationNameMultiMapIterator SNIterator;
8530  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8531  bool FoundFlag, ErasedFlag = false;
8532 
8533  if(SNRange.first != SNRange.second)
8534  {
8535  SNRange.first--; // now pointing to before the first
8536  SNRange.second--; // now pointing to the last
8537  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8538  {
8539  // Same elements are in Done map as in name map
8540  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8541  {
8542  ErasedFlag = true;
8543  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8544  TVIt->LocationName = "";
8545  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8546  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8547  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8548  {
8549  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8550  if(FoundFlag)
8551  {
8552  TrackElementAt(20, Position).LocationName = "";
8553  TrackElementAt(21, Position).ActiveTrackElementName = "";
8554  }
8555  }
8556  // erase name in name map
8557 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8558  }
8559  }
8560  }
8561  if(ErasedFlag)
8562  {
8564  }
8565  if(TrackFinished)
8566  {
8568  }
8569 // set here as well as in LinkTrack so don't have to link track just because a name added
8570 // if track not finished then will be set when track validated
8571 
8572 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8573 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8574 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8575 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8576 // so the error would be seen.
8577 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8578  std::pair<AnsiString, char>TempMapPair;
8579 
8580  ContinuationNameMap.clear();
8581  for(int x = 0; x < Track->TrackVectorSize(); x++)
8582  {
8583  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8584  {
8585  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8586  TempMapPair.second = 'x'; // unused
8587  ContinuationNameMap.insert(TempMapPair);
8588  }
8589  }
8590 //end of addition
8591  CheckLocationNameMultiMap(1); // test
8592  Utilities->CallLogPop(562);
8593 }
8594 
8595 // ---------------------------------------------------------------------------
8596 
8597 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8598 /*
8599  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8600  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8601 */
8602 {
8603  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8604  AnsiString(SpeedTag));
8605  if(!NamedLocationElementAt(2, HLoc, VLoc))
8606  {
8607  Utilities->CallLogPop(948);
8608  return(false);
8609  }
8610  bool FoundFlag;
8611  int Position = -1;
8612  TIMPair IMPair;
8613 
8614  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8615  {
8616  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8617  if(FoundFlag)
8618  {
8619  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8620  {
8621  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8622  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8623  // don't allow duplicates in either list, or processing takes a lot longer
8624  {
8625  FoundElement = MapPos;
8626  Utilities->CallLogPop(563);
8627  return(true);
8628  }
8629  }
8630  }
8631  }
8632  else
8633  {
8634  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8635  if(FoundFlag)
8636  {
8637  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8638  {
8639  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8640  {
8641  FoundElement = IMPair.first;
8642  Utilities->CallLogPop(564);
8643  return(true);
8644  }
8645  }
8646  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8647  {
8648  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8649  {
8650  FoundElement = IMPair.second;
8651  Utilities->CallLogPop(565);
8652  return(true);
8653  }
8654  }
8655  }
8656  }
8657  Utilities->CallLogPop(566);
8658  return(false);
8659 }
8660 
8661 // ---------------------------------------------------------------------------
8662 
8663 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8664 /*
8665  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8666  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8667  with the new name
8668 */
8669 {
8670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8671  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8672 
8673  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8674  int HLoc = TrackElement->HLoc;
8675  int VLoc = TrackElement->VLoc;
8676  bool FoundFlag;
8677 
8678  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8679  // only have timetable names for adjacent platforms & named locations
8680  {
8681  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8682  if(FoundFlag)
8683  {
8684  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8685  }
8686  }
8687  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8688 
8689  if(ErrorString != "")
8690  {
8691  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8692  }
8693  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8694  CheckLocationNameMultiMap(2); // test
8695  Utilities->CallLogPop(567);
8696 }
8697 
8698 // ---------------------------------------------------------------------------
8699 
8700 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8701 /*
8702  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8703 */
8704 {
8705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8706  if(LNDone2MultiMap.empty())
8707  {
8708  Utilities->CallLogPop(568);
8709  return(false);
8710  }
8711  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8712 
8713  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8714  {
8715  if(LNDone2MultiMapIterator->second == MapPos)
8716  {
8717  Utilities->CallLogPop(569);
8718  return(true);
8719  }
8720  }
8721  Utilities->CallLogPop(570);
8722  return(false);
8723 }
8724 
8725 // ---------------------------------------------------------------------------
8726 
8727 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8728 /*
8729  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8730 */
8731 {
8732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8733  if(LNPendingList.empty())
8734  {
8735  Utilities->CallLogPop(571);
8736  return(false);
8737  }
8738  TLNPendingListIterator LNPendingListIterator;
8739 
8740  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8741  {
8742  if(*LNPendingListIterator == MapPos)
8743  {
8744  Utilities->CallLogPop(572);
8745  return(true);
8746  }
8747  }
8748  Utilities->CallLogPop(573);
8749  return(false);
8750 }
8751 
8752 // ---------------------------------------------------------------------------
8753 
8754 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8755 /*
8756  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8757 */
8758 {
8759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8760  THVPair HVPair(HLoc, VLoc);
8761  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8762  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8763 
8764  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8765  {
8766  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8767  {
8768  Utilities->CallLogPop(574);
8769  return(true);
8770  }
8771  }
8772  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8773  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8774  {
8775  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8776  {
8777  Utilities->CallLogPop(575);
8778  return(true);
8779  }
8780  }
8781  Utilities->CallLogPop(576);
8782  return(false);
8783 }
8784 
8785 // ---------------------------------------------------------------------------
8786 
8787 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8788 {
8789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8790  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8791  {
8792  Utilities->CallLogPop(1953);
8793  return(true);
8794  }
8795  Utilities->CallLogPop(1954);
8796  return(false);
8797 }
8798 
8799 // ---------------------------------------------------------------------------
8800 
8801 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8802 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8803 //program and used when try to save as a .rly file
8804 {
8805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8808  if(LocationNameMultiMap.empty()) //no names so no duplicates
8809  {
8810  Utilities->CallLogPop(2254);
8811  return(false);
8812  }
8813  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8814  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8815  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8816  {
8818  {
8819  if(GiveMessage)
8820  {
8821  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8822  }
8823  Utilities->CallLogPop(2255);
8824  return(true);
8825  }
8826  }
8827  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8828  {
8829  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8830  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8831  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8832  {
8834  {
8835  if(GiveMessage)
8836  {
8837  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8838  }
8839  Utilities->CallLogPop(2256);
8840  return(true);
8841  }
8842  }
8843  }
8844  Utilities->CallLogPop(2257);
8845  return(false); //OK, no duplicates
8846 }
8847 
8848 // ---------------------------------------------------------------------------
8849 
8851 {
8852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8853  THVPair HVPair;
8854  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8855  //for use in the duplicate check
8856  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8857  {
8858  if(LNMMIt->second < 0) //active track element
8859  {
8860  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8861  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8862  }
8863  else //inactive track element
8864  {
8865  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8866  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8867  }
8868  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8869  }
8870  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8871 
8872  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8873  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8874  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8875 
8876  std::list<THVPair> HVLinkedList;
8877 
8878  //set the first value to true and add it to the list
8879  HVPairsLinkedMap.begin()->second = true;
8880  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8881  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8882  //examination
8883  THVPair HVPairUnderExamination;
8884  THVPairsLinkedMap::iterator HVPLMIt;
8885  THVPair HVPairNew;
8886  while(!HVLinkedList.empty())
8887  {
8888  HVPairUnderExamination = HVLinkedList.front();
8889  HVLinkedList.pop_front();
8890  HVPairNew.first = HVPairUnderExamination.first;
8891  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8892  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8893  if(HVPLMIt != HVPairsLinkedMap.end())
8894  {
8895  if(!HVPLMIt->second)
8896  {
8897  HVLinkedList.push_back(HVPLMIt->first);
8898  }
8899  HVPLMIt->second = true;
8900  }
8901  HVPairNew.first = HVPairUnderExamination.first - 1;
8902  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8903  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8904  if(HVPLMIt != HVPairsLinkedMap.end())
8905  {
8906  if(!HVPLMIt->second)
8907  {
8908  HVLinkedList.push_back(HVPLMIt->first);
8909  }
8910  HVPLMIt->second = true;
8911  }
8912  HVPairNew.first = HVPairUnderExamination.first;
8913  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8914  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8915  if(HVPLMIt != HVPairsLinkedMap.end())
8916  {
8917  if(!HVPLMIt->second)
8918  {
8919  HVLinkedList.push_back(HVPLMIt->first);
8920  }
8921  HVPLMIt->second = true;
8922  }
8923  HVPairNew.first = HVPairUnderExamination.first + 1;
8924  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8925  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8926  if(HVPLMIt != HVPairsLinkedMap.end())
8927  {
8928  if(!HVPLMIt->second)
8929  {
8930  HVLinkedList.push_back(HVPLMIt->first);
8931  }
8932  HVPLMIt->second = true;
8933  }
8934  }
8935 
8936  //at the end if any have a false bool then the name is duplicated so return false
8937  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8938  {
8939  if(!HVPLMIt->second)
8940  {
8941  Utilities->CallLogPop(2258);
8942  return(false);
8943  }
8944  }
8945  Utilities->CallLogPop(2259);
8946  return(true);
8947 }
8948 
8949 // ---------------------------------------------------------------------------
8950 
8951 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8952 /*
8953  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8954 */
8955 
8956 {
8957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8958  if(LocationName == "")
8959  {
8960  Utilities->CallLogPop(577);
8961  return(false);
8962  }
8963 // new for v0.2b
8964 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8966  {
8967  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8968  ActiveTrackElementNameMap.clear();
8969  for(unsigned int x = 0; x < TrackVector.size(); x++)
8970  {
8971  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8972  == ContinuationNameMap.end())
8973  {
8974  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8975  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8976  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8977  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8978  }
8979  }
8981  }
8982  Utilities->CallLogPop(578);
8983  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8984 // end of new section
8985 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8986 }
8987 
8988 // ---------------------------------------------------------------------------
8989 
8990 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8991 /*
8992  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8993  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8994  new names in the vectors.
8995 */
8996 {
8997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8998  bool FoundFlag, ErasedFlag = false;
8999  TLocationNameMultiMapIterator SNIterator;
9000  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9001 
9002  if(SNRange.first != SNRange.second)
9003  {
9004  ErasedFlag = true;
9005  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9006  {
9007  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9008  TVIt->LocationName = "";
9009  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9010  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9011  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9012  {
9013  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9014  if(FoundFlag)
9015  {
9016  TrackElementAt(25, Position).LocationName = "";
9017  TrackElementAt(26, Position).ActiveTrackElementName = "";
9018  }
9019  }
9020  }
9021  }
9022  if(ErasedFlag)
9023  {
9025  }
9026  CheckLocationNameMultiMap(3); // test
9027  Utilities->CallLogPop(579);
9028 }
9029 
9030 // ---------------------------------------------------------------------------
9031 
9032 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9033 /*
9034  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9035  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9036  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9037  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
9038  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
9039  naming up to date with the deletion or insertion.
9040 */
9041 {
9042  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9043  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9044  LNPendingList.clear();
9045  AnsiString LocationName;
9046  int MapPos;
9047  bool FoundFlag = 0;
9048 
9049 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9050  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9051  if(FoundFlag)
9052  {
9053  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9054  if(LocationName != "")
9055  {
9056  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9057  EnterLocationName(13, LocationName, true);
9058  Utilities->CallLogPop(2251);
9059  return;
9060  }
9061  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9062  if(LocationName != "")
9063  {
9064  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9065  EnterLocationName(14, LocationName, true);
9066  Utilities->CallLogPop(2252);
9067  return;
9068  }
9069  }
9070 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9071 
9072  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9073  if(FoundFlag)
9074  {
9075  LocationName = TrackElementAt(1004, Position).LocationName;
9076  if(LocationName != "")
9077  {
9078  int ModifiedPosition = -1 - Position;
9079  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9080  EnterLocationName(15, LocationName, true);
9081  Utilities->CallLogPop(2253);
9082  return;
9083  }
9084  }
9085  if(SpeedTag == 76) // top plat
9086  {
9087  for(int x = 0; x < 25; x++)
9088  {
9089  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9090  {
9091  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9092  EnterLocationName(3, LocationName, true);
9093  break;
9094  }
9095  }
9096  }
9097  else if(SpeedTag == 77) // bot plat
9098  {
9099  for(int x = 0; x < 25; x++)
9100  {
9101  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9102  {
9103  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9104  EnterLocationName(4, LocationName, true);
9105  break;
9106  }
9107  }
9108  }
9109  else if(SpeedTag == 78) // l plat
9110  {
9111  for(int x = 0; x < 25; x++)
9112  {
9113  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9114  {
9115  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9116  EnterLocationName(5, LocationName, true);
9117  break;
9118  }
9119  }
9120  }
9121  else if(SpeedTag == 79) // r plat
9122  {
9123  for(int x = 0; x < 25; x++)
9124  {
9125  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9126  {
9127  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9128  EnterLocationName(6, LocationName, true);
9129  break;
9130  }
9131  }
9132  }
9133  else if(SpeedTag == 96) // conc
9134  {
9135  for(int x = 0; x < 28; x++)
9136  {
9137  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9138  {
9139  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9140  EnterLocationName(7, LocationName, true);
9141  break;
9142  }
9143  }
9144  }
9145  else if(SpeedTag == 129) // vert footbridge
9146  {
9147  for(int x = 0; x < 8; x++)
9148  {
9149  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9150  {
9151  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9152  EnterLocationName(8, LocationName, true);
9153  break;
9154  }
9155  }
9156  }
9157  else if(SpeedTag == 130) // hor footbridge
9158  {
9159  for(int x = 0; x < 8; x++)
9160  {
9161  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9162  {
9163  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9164  EnterLocationName(9, LocationName, true);
9165  break;
9166  }
9167  }
9168  }
9169  else if(SpeedTag == 145) // vert u'pass
9170  {
9171  for(int x = 0; x < 8; x++)
9172  {
9173  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9174  {
9175  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9176  EnterLocationName(11, LocationName, true);
9177  break;
9178  }
9179  }
9180  }
9181  else if(SpeedTag == 146) // hor u'pass
9182  {
9183  for(int x = 0; x < 8; x++)
9184  {
9185  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9186  {
9187  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9188  EnterLocationName(12, LocationName, true);
9189  break;
9190  }
9191  }
9192  }
9193  else if(SpeedTag == 131) // named location
9194  {
9195  for(int x = 0; x < 4; x++)
9196  {
9197  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9198  {
9199  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9200  EnterLocationName(10, LocationName, true);
9201  break;
9202  }
9203  }
9204  }
9205 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9206  Utilities->CallLogPop(580);
9207 }
9208 
9209 // ---------------------------------------------------------------------------
9210 
9211 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9212 /*
9213  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9214  true if a LocationName is found, and also returns the name and the adjusted vector position.
9215 */
9216 {
9217  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9218  AnsiString(SpeedTag));
9219  bool FoundFlag;
9220  TIMPair IMPair;
9221  TTrackVectorIterator TempElement;
9222  int Position;
9223 
9224  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9225  if(FoundFlag)
9226  {
9227  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9228  {
9229  TempElement = InactiveTrackVector.begin() + IMPair.first;
9230  if(TempElement->LocationName != "")
9231  {
9232  LocationName = TempElement->LocationName;
9233  FoundElement = IMPair.first;
9234  Utilities->CallLogPop(581);
9235  return(true);
9236  }
9237  }
9238  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9239  {
9240  TempElement = InactiveTrackVector.begin() + IMPair.second;
9241  if(TempElement->LocationName != "")
9242  {
9243  LocationName = TempElement->LocationName;
9244  FoundElement = IMPair.second;
9245  Utilities->CallLogPop(582);
9246  return(true);
9247  }
9248  }
9249  }
9250  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9251  if(FoundFlag)
9252  {
9253  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9254  {
9255  TempElement = TrackVector.begin() + Position;
9256  if(TempElement->LocationName != "")
9257  {
9258  LocationName = TempElement->LocationName;
9259  FoundElement = -1 - Position;
9260  Utilities->CallLogPop(583);
9261  return(true);
9262  }
9263  }
9264  }
9265  Utilities->CallLogPop(584);
9266  return(false);
9267 }
9268 
9269 // ---------------------------------------------------------------------------
9270 
9271 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9272 {
9273 // check quantity in map & vectors match
9274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9275  unsigned int Count = 0;
9276 
9277  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9278  {
9279  Utilities->CallLogPop(2059);
9280  return;
9281  }
9282  AnsiString SName, TName, ErrorString;
9283 
9284  for(unsigned int x = 0; x < TrackVector.size(); x++)
9285  {
9286  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9287  {
9288  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9289  {
9290  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9291  AnsiString(Caller));
9292  }
9293  Count++;
9294  }
9295  }
9296  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9297  {
9298  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9299  {
9300  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9301  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9302  {
9303  throw Exception
9304  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9305  AnsiString(Caller));
9306  }
9307  Count++;
9308  }
9309  }
9310  if(LocationNameMultiMap.size() != Count)
9311  {
9312  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9313  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9314  }
9315 // check all entries in both vectors match entries in name multimap
9317 
9318  for(unsigned int x = 0; x < TrackVector.size(); x++)
9319  {
9320  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9321  {
9322  SName = TrackElementAt(1365, x).LocationName;
9323  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9324  if(ErrorString != "")
9325  {
9326  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9327  }
9328  if(SNIt->second != -1 - (int)x)
9329  {
9330  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9331  AnsiString(Caller));
9332  }
9333  }
9334  // check corresponding platform for all Timetable entries that aren't empty
9335  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9336  TIMPair IMPair;
9337  bool FoundFlag = false;
9338  if(TName != "")
9339  {
9340  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9341  if(FoundFlag)
9342  {
9343  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9345  {
9346  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9347  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9348  }
9349  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9350  {
9351  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9352  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9353  AnsiString(Caller));
9354  }
9355  }
9356  else
9357  {
9358  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9359  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9360  }
9361  }
9362  }
9363  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9364  {
9365  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9366  {
9367  SName = InactiveTrackElementAt(148, x).LocationName;
9368  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9369  if(ErrorString != "")
9370  {
9371  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9372  }
9373  if(SNIt->second != (int)x)
9374  {
9375  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9376  AnsiString(Caller));
9377  }
9378  }
9379  }
9380  Utilities->CallLogPop(585);
9381 }
9382 
9383 // ---------------------------------------------------------------------------
9384 
9386  AnsiString &ErrorString)
9387 {
9388 /*
9389  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9390  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9391  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9392 */
9393  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9394  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9395  ErrorString = "";
9396  bool FoundFlag = false;
9397  TLocationNameMultiMapIterator SNIterator;
9398  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9399 
9400  if(SNRange.first == SNRange.second)
9401  {
9402  ErrorString = "Error, Name " + LocationName + " not found in map";
9403  Utilities->CallLogPop(586);
9404  return(SNRange.first);
9405  }
9406  else
9407  {
9408  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9409  {
9410  if(SNIterator->second < 0)
9411  {
9412  int TVPos = -1 - SNIterator->second;
9413  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9414  if(TVIt == TrackElement)
9415  {
9416  FoundFlag = true;
9417  Utilities->CallLogPop(587);
9418  return(SNIterator);
9419  }
9420  }
9421  else
9422  {
9423  int ITVPos = SNIterator->second;
9424  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9425  if(ITVIt == TrackElement)
9426  {
9427  FoundFlag = true;
9428  Utilities->CallLogPop(588);
9429  return(SNIterator);
9430  }
9431  }
9432  }
9433  }
9434  if(!FoundFlag)
9435  {
9436  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9437  }
9438  Utilities->CallLogPop(589);
9439  return(SNIterator);
9440 }
9441 
9442 // ---------------------------------------------------------------------------
9443 
9444 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9445 {
9446 /*
9447  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9448  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9449 */
9450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9451  TLocationNameMultiMapEntry LocationNameEntry;
9452 
9453  LocationNameEntry.first = NewName;
9454  LocationNameEntry.second = SNIterator->second;
9455  LocationNameMultiMap.erase(SNIterator);
9456  LocationNameMultiMap.insert(LocationNameEntry);
9457  Utilities->CallLogPop(590);
9458 }
9459 
9460 // ---------------------------------------------------------------------------
9461 
9463 {
9464 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9466  if(Position < 0) // footcrossing
9467  {
9468  int TruePos = -1 - Position;
9469  // new check at v0.2b
9470  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9471  {
9472  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9473  }
9474  Utilities->CallLogPop(591);
9475  return (TrackVector.begin() + TruePos);
9476  }
9477  else
9478  {
9479  // new check at v0.2b
9480  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9481  {
9482  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9483  }
9484  Utilities->CallLogPop(592);
9485  return (InactiveTrackVector.begin() + Position);
9486  }
9487 }
9488 
9489 // ---------------------------------------------------------------------------
9490 
9491 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9492 {
9493 /*
9494  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9495  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9496  LocationNameMultiMap.
9497 */
9498  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9499  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9500  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9501 
9502  if(!InactiveTrack2MultiMap.empty())
9503  {
9504  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9505  InactiveTrack2MultiMapIterator++)
9506  {
9507  if(InactiveTrack2MultiMapIterator->second > VecPos)
9508  {
9509  InactiveTrack2MultiMapIterator->second--;
9510  }
9511  // can't be == VecPos as that position erased
9512  }
9513  }
9514  if(!LocationNameMultiMap.empty())
9515  {
9516  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9517  LocationNameMultiMapIterator++)
9518  {
9519  if(LocationNameMultiMapIterator->second < 0)
9520  {
9521  continue; // deal with TrackVectors separately
9522  }
9523  if(LocationNameMultiMapIterator->second > (int)VecPos)
9524  {
9525  LocationNameMultiMapIterator->second--;
9526  }
9527  }
9528  }
9529  Utilities->CallLogPop(593);
9530 }
9531 
9532 // ---------------------------------------------------------------------------
9533 
9534 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9535 {
9536 /*
9537  After an element has been erased from the track vector, all the later elements are moved down one. This function
9538  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9539  LocationNameMultiMap.
9540 */
9541  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9542  TTrackMapIterator TrackMapIterator;
9543  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9544 
9545  if(!TrackMap.empty())
9546  {
9547  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9548  {
9549  if(TrackMapIterator->second > VecPos)
9550  {
9551  TrackMapIterator->second--;
9552  }
9553  // can't be == VecPos as that position erased
9554  }
9555  }
9556  if(!LocationNameMultiMap.empty())
9557  {
9558  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9559  LocationNameMultiMapIterator++)
9560  {
9561  if(LocationNameMultiMapIterator->second >= 0)
9562  {
9563  continue; // deal with InactiveTrackVectors separately
9564  }
9565  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9566  // Val -1 -2 -3 -4 -5 -6 -7 -8
9567  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9568  {
9569  LocationNameMultiMapIterator->second++;
9570  }
9571  }
9572  }
9573  for(unsigned int x = 0; x < TrackVector.size(); x++)
9574  {
9575  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9576  if(TkEl.TrackType == GapJump)
9577  {
9578  // position 0 is the gap
9579  if(TkEl.Conn[0] == int(VecPos))
9580  {
9581  TkEl.Conn[0] = -1; // connected to a deleted gap
9582  continue;
9583  }
9584  if(TkEl.Conn[0] > int(VecPos))
9585  {
9586  TkEl.Conn[0]--;
9587  }
9588  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9589  {
9590  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9591  {
9592  TkEl.Conn[0] = -1;
9593  }
9594  }
9595  }
9596  }
9597  Utilities->CallLogPop(1433);
9598 }
9599 
9600 // ---------------------------------------------------------------------------
9601 
9603 /*
9604  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9605  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9606  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9607 */
9608 {
9609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9610  LocationNameMultiMap.clear();
9611  TLocationNameMultiMapEntry LocationNameEntry;
9612  TTrackElement TrackElement;
9613 
9614  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9615  {
9616  TrackElement = TrackElementAt(1376, TVPos);
9617  if(TrackElement.FixedNamedLocationElement)
9618  {
9619  LocationNameEntry.first = TrackElement.LocationName;
9620  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9621  LocationNameMultiMap.insert(LocationNameEntry);
9622  }
9623  }
9624 
9625  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9626  {
9627  TrackElement = InactiveTrackElementAt(149, ITVPos);
9628  if(TrackElement.FixedNamedLocationElement)
9629  {
9630  LocationNameEntry.first = TrackElement.LocationName;
9631  LocationNameEntry.second = ITVPos;
9632  LocationNameMultiMap.insert(LocationNameEntry);
9633  }
9634  }
9635  Utilities->CallLogPop(594);
9636 }
9637 
9638 // ---------------------------------------------------------------------------
9639 
9641 // Return true if there is a named location present in the railway
9642 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9643 {
9644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9645  TTrackVectorIterator ITVI;
9646 
9647  if(InactiveTrackVector.empty())
9648  {
9649  Utilities->CallLogPop(1343);
9650  return(false);
9651  }
9652  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9653  {
9654  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9655  {
9656  Utilities->CallLogPop(1404);
9657  return(true);
9658  }
9659  }
9660  Utilities->CallLogPop(1344);
9661  return(false);
9662 }
9663 
9664 // ---------------------------------------------------------------------------
9665 
9667 /*
9668  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9669 */
9670 {
9671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9672 // ResetDistanceElements(6);
9673  for(unsigned int x = 0; x < TrackVector.size(); x++)
9674  {
9675  TTrackElement &TE = TrackElementAt(718, x);
9678  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9679  {
9682  }
9683  }
9684 /* old function
9685  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9686  {
9687  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9688  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9689  }
9690  else
9691  {
9692  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9693  }
9694  }
9695 */
9696  Utilities->CallLogPop(617);
9697 }
9698 
9699 // ---------------------------------------------------------------------------
9700 
9701 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9702 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9703 {
9704  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9705  for(unsigned int x = 0; x < TrackVector.size(); x++)
9706  {
9707  TTrackElement TempElement = TrackElementAt(1377, x);
9708  if(TempElement.Length01 > -1)
9709  {
9710  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9711  }
9712  if(TempElement.Length23 > -1)
9713  {
9714  MarkOneLength(2, TempElement, false, Disp);
9715  }
9716  }
9717  Disp->Update();
9718  Utilities->CallLogPop(618);
9719 }
9720 
9721 // ---------------------------------------------------------------------------
9722 
9723 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9724 /*
9725  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9726  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9727  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9728  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9729  track as indicated by FirstTrack (true for track01 & false for track23).
9730 */
9731 {
9732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9733  AnsiString((short)FirstTrack));
9734  bool LengthDifferent = false, SpeedDifferent = false;
9735 
9736  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9737  {
9738  Utilities->CallLogPop(619);
9739  return;
9740  }
9741  int EXArray[16][2] =
9742  {{4, 6}, {2, 8}, // horizontal & vertical
9743  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9744  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9745  {1, 9}, {3, 7}}; // forward & reverse diagonals
9746 
9747  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9748  Graphics::TBitmap *Bitmap;
9749 
9750  if(FirstTrack)
9751  {
9752  InLink = TrackElement.Link[0];
9753  OutLink = TrackElement.Link[1];
9754  }
9755  else
9756  {
9757  InLink = TrackElement.Link[2];
9758  OutLink = TrackElement.Link[3];
9759  }
9760  for(int x = 0; x < 16; x++)
9761  {
9762  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9763  {
9764  Index = x;
9765  }
9766  }
9767  if(Index == -1)
9768  {
9769  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9770  }
9771 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9772  the graphic for each of which is different because of the shape of the overbridge. The basic
9773  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9774  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9775  int BrEXArray[24][2] = {
9776  {4,6},{2,8},{1,9},{3,7},
9777  {1,9},{3,7},{1,9},{3,7},
9778  {2,8},{4,6},{2,8},{4,6}
9779 */
9780  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9781  {
9782  if(Index == 1)
9783  {
9784  if(TrackElement.SpeedTag == 49)
9785  {
9786  BrNum = 1 + 16;
9787  }
9788  else if(TrackElement.SpeedTag == 54)
9789  {
9790  BrNum = 8 + 16;
9791  }
9792  else if(TrackElement.SpeedTag == 55)
9793  {
9794  BrNum = 10 + 16;
9795  }
9796  }
9797  else if(Index == 0)
9798  {
9799  if(TrackElement.SpeedTag == 48)
9800  {
9801  BrNum = 0 + 16;
9802  }
9803  else if(TrackElement.SpeedTag == 58)
9804  {
9805  BrNum = 11 + 16;
9806  }
9807  else if(TrackElement.SpeedTag == 59)
9808  {
9809  BrNum = 9 + 16;
9810  }
9811  }
9812  else if(Index == 14)
9813  {
9814  if(TrackElement.SpeedTag == 50)
9815  {
9816  BrNum = 2 + 16;
9817  }
9818  else if(TrackElement.SpeedTag == 52)
9819  {
9820  BrNum = 4 + 16;
9821  }
9822  else if(TrackElement.SpeedTag == 57)
9823  {
9824  BrNum = 6 + 16;
9825  }
9826  }
9827  else if(Index == 15)
9828  {
9829  if(TrackElement.SpeedTag == 51)
9830  {
9831  BrNum = 3 + 16;
9832  }
9833  else if(TrackElement.SpeedTag == 53)
9834  {
9835  BrNum = 7 + 16;
9836  }
9837  else if(TrackElement.SpeedTag == 56)
9838  {
9839  BrNum = 5 + 16;
9840  }
9841  }
9842  }
9843  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9844  {
9845  GrNum = BrNum;
9846  }
9847  else
9848  {
9849  GrNum = Index;
9850  }
9851  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9852  {
9853  if(GrNum > 15) // underbridge
9854  {
9855  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9856  }
9857  else
9858  {
9859  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9860  }
9861  if(TrackElement.SpeedTag == 64)
9862  {
9863  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9864  }
9865  if(TrackElement.SpeedTag == 65)
9866  {
9868  }
9869  if(TrackElement.SpeedTag == 66)
9870  {
9872  }
9873  if(TrackElement.SpeedTag == 67)
9874  {
9876  }
9877  if(TrackElement.SpeedTag == 80)
9878  {
9879  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9880  }
9881  if(TrackElement.SpeedTag == 81)
9882  {
9884  }
9885  if(TrackElement.SpeedTag == 82)
9886  {
9888  }
9889  if(TrackElement.SpeedTag == 83)
9890  {
9892  }
9893  if(TrackElement.SpeedTag == 84)
9894  {
9896  }
9897  if(TrackElement.SpeedTag == 85)
9898  {
9900  }
9901  if(TrackElement.SpeedTag == 86)
9902  {
9904  }
9905  if(TrackElement.SpeedTag == 87)
9906  {
9908  }
9909  if(TrackElement.SpeedTag == 129)
9910  {
9911  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9912  }
9913  if(TrackElement.SpeedTag == 130)
9914  {
9916  }
9917  }
9918 
9919  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9920  {
9921  if(GrNum > 15) // underbridge
9922  {
9923  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9924  }
9925  else
9926  {
9927  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9928  }
9929  if(TrackElement.SpeedTag == 64)
9930  {
9931  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9932  }
9933  if(TrackElement.SpeedTag == 65)
9934  {
9935  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9936  }
9937  if(TrackElement.SpeedTag == 66)
9938  {
9939  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9940  }
9941  if(TrackElement.SpeedTag == 67)
9942  {
9943  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9944  }
9945  if(TrackElement.SpeedTag == 80)
9946  {
9947  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9948  }
9949  if(TrackElement.SpeedTag == 81)
9950  {
9951  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9952  }
9953  if(TrackElement.SpeedTag == 82)
9954  {
9955  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9956  }
9957  if(TrackElement.SpeedTag == 83)
9958  {
9959  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9960  }
9961  if(TrackElement.SpeedTag == 84)
9962  {
9963  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9964  }
9965  if(TrackElement.SpeedTag == 85)
9966  {
9967  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9968  }
9969  if(TrackElement.SpeedTag == 86)
9970  {
9971  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9972  }
9973  if(TrackElement.SpeedTag == 87)
9974  {
9975  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9976  }
9977  if(TrackElement.SpeedTag == 129)
9978  {
9979  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9980  }
9981  if(TrackElement.SpeedTag == 130)
9982  {
9983  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9984  }
9985  }
9986 
9987  else // SpeedDifferent only: red - use non sig graphics
9988  {
9989  if(GrNum > 15) // underbridge
9990  {
9991  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9992  }
9993  else
9994  {
9995  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9996  }
9997  if(TrackElement.SpeedTag == 64)
9998  {
9999  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10000  }
10001  if(TrackElement.SpeedTag == 65)
10002  {
10004  }
10005  if(TrackElement.SpeedTag == 66)
10006  {
10008  }
10009  if(TrackElement.SpeedTag == 67)
10010  {
10012  }
10013  if(TrackElement.SpeedTag == 80)
10014  {
10015  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10016  }
10017  if(TrackElement.SpeedTag == 81)
10018  {
10020  }
10021  if(TrackElement.SpeedTag == 82)
10022  {
10024  }
10025  if(TrackElement.SpeedTag == 83)
10026  {
10028  }
10029  if(TrackElement.SpeedTag == 84)
10030  {
10032  }
10033  if(TrackElement.SpeedTag == 85)
10034  {
10036  }
10037  if(TrackElement.SpeedTag == 86)
10038  {
10040  }
10041  if(TrackElement.SpeedTag == 87)
10042  {
10044  }
10045  if(TrackElement.SpeedTag == 129)
10046  {
10047  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10048  }
10049  if(TrackElement.SpeedTag == 130)
10050  {
10052  }
10053  }
10054  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10055  Utilities->CallLogPop(620);
10056 }
10057 
10058 // ---------------------------------------------------------------------------
10059 
10060 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10061 /* FirstTrack = LinkPos's 0 & 1
10062  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10063 */
10064 {
10065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
10066  AnsiString((short)FirstTrack));
10067  LengthDifferent = false;
10068  SpeedDifferent = false;
10069  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10070  {
10071  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10072  {
10073  LengthDifferent = true;
10074  }
10075  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10076  {
10077  SpeedDifferent = true;
10078  }
10079  if(LengthDifferent || SpeedDifferent)
10080  {
10081  Utilities->CallLogPop(625);
10082  return(false);
10083  }
10084  Utilities->CallLogPop(626);
10085  return(true);
10086  }
10087 
10088  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10089  {
10090  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10091  {
10092  LengthDifferent = true;
10093  }
10094  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10095  {
10096  SpeedDifferent = true;
10097  }
10098  if(LengthDifferent || SpeedDifferent)
10099  {
10100  Utilities->CallLogPop(627);
10101  return(false);
10102  }
10103  Utilities->CallLogPop(628);
10104  return(true);
10105  }
10106 
10107  else // any other 1 track element, including platforms being present
10108  {
10109  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10110  {
10111  LengthDifferent = true;
10112  }
10113  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10114  {
10115  SpeedDifferent = true;
10116  }
10117  if(LengthDifferent || SpeedDifferent)
10118  {
10119  Utilities->CallLogPop(629);
10120  return(false);
10121  }
10122  Utilities->CallLogPop(630);
10123  return(true);
10124  }
10125 }
10126 
10127 // ---------------------------------------------------------------------------
10128 
10129 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10130 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10131 {
10132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10133  AnsiString(VLoc));
10134  bool FoundFlag;
10135  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10136 
10137  if(!FoundFlag)
10138  {
10139  Utilities->CallLogPop(633);
10140  return(false);
10141  }
10142  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10143  {
10144  Utilities->CallLogPop(634);
10145  return(true); // only need to check first since if second is a platform the the first must be too
10146  }
10147  else
10148  {
10149  Utilities->CallLogPop(635);
10150  return(false);
10151  }
10152 }
10153 
10154 // ---------------------------------------------------------------------------
10155 
10156 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10157 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10158 {
10159  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10160  AnsiString(VLoc));
10161  bool FoundFlag;
10162  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10163 
10164  if(!FoundFlag)
10165  {
10166  Utilities->CallLogPop(636);
10167  return(false);
10168  }
10170  {
10171  Utilities->CallLogPop(637);
10172  return(true); // only need to check first since only one used for NamedNonStationLocations
10173  }
10174  else
10175  {
10176  Utilities->CallLogPop(638);
10177  return(false);
10178  }
10179 }
10180 
10181 // ---------------------------------------------------------------------------
10182 
10184 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10185  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10186  the front of train stop points for each direction.
10187  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10188  end (unless buffers at one or both ends in which case stop points are the end elements).
10189  Note that for a single element the stop point is the element itself (formula doesn't apply).
10190  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10191  repeating the procedure for every element. At the end all unused values are returned to -1.
10192  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10193 */
10194 {
10195  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10196  TTrackElement TempElement, StartElement;
10197  AnsiString TempName;
10198  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10199  bool ForwardSet, ReverseSet;
10200 
10201  for(unsigned int x = 0; x < TrackVector.size(); x++)
10202  {
10205  }
10206  for(unsigned int x = 0; x < TrackVector.size(); x++)
10207  {
10208  ForwardSet = false;
10209  ReverseSet = false;
10210  TempElement = TrackElementAt(1380, x);
10211  VecPos = x;
10212  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
10213  // 2nd condition incl so don't re-examine elements with stop links set to 5
10214  {
10215  TempName = TempElement.ActiveTrackElementName;
10216  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10217  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10218  // an element linked at both ends where both links are also named elements
10219  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10220  {
10221  continue; // looking for an end element so skip this one
10222  }
10223  else // reached one end
10224  {
10225  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10226  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10227  // single named element linked at both ends
10228  {
10229  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10230  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10231  continue;
10232  }
10233  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10234  // single named buffer element (LinkPos 1 is the non-buffer end)
10235  {
10236  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10237  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10238  continue;
10239  }
10240  else
10241  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10242  // and platforms always on straight (conns 0 & 1) section of points
10243  {
10244  for(int y = 0; y < 2; y++)
10245  {
10246  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10247  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10248 /* TTrackElement Temp1 = TempElement;
10249  ***********New section, compiles but not checked - does bit below need to be else if?
10250  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10251  {
10252  //search along Dir direction until find other end, skip if Dir facing buffer end
10253  int NewDir = Dir;
10254  int NewVecPos;
10255  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10256  {
10257  NewVecPos = Temp1.Conn[NewDir];
10258  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10259  Temp1 = TrackElementAt(601, NewVecPos);
10260  }
10261  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10262  {
10263  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10264  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10265  }
10266  }
10267  ***************
10268 */
10269  // end may be linked at both ends but only one link named, or buffer with linked element named
10270  // if a buffer then the named linkpos has to be 1
10271  // already dealt with all types of single element so at least 2 linked named element
10272  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10273  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10274  {
10275  StartElement = TempElement;
10276  StartVecPos = VecPos;
10277  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10278  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10279  EntryPos = 1 - Dir;
10280  StartEntryPos = 1 - Dir;
10281  Count = 1;
10282  // work along named elements until find the other end
10283  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10284  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10285  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10286  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10287  // all stop link pos's are set to 5
10288  {
10289  VecPos = TempElement.Conn[1 - EntryPos];
10290  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10291  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10292  EntryPos = TempEntryPos;
10293  Count++;
10294  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10295  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10296  }
10297  // here when reached other end, maybe buffers, continuation or last named linked element
10298  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10299  // terminal station, set end elements as stop elements
10300  {
10301  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10302  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10303  continue;
10304  }
10305  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10306  // terminal station, set end elements as stop elements
10307  {
10308  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10309  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10310  continue;
10311  }
10312  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10313  // NonStationLocation so set end elements as stop elements
10314  {
10315  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10316  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10317  continue;
10318  }
10319  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10320  ForwardNumber = ((Count + 1) / 2) + 1;
10321  ReverseNumber = (Count - ForwardNumber) + 1;
10322  Count = 1; // starting value
10323  EntryPos = 1 - Dir;
10324  TempElement = StartElement;
10325  VecPos = StartVecPos;
10326  if(Count == ForwardNumber)
10327  {
10328  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10329  ForwardSet = true;
10330  }
10331  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10332  {
10333  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10334  ReverseSet = true;
10335  }
10336  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10337  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10338  {
10339  VecPos = TempElement.Conn[1 - EntryPos];
10340  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10341  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10342  EntryPos = TempEntryPos;
10343  Count++;
10344  if(Count == ForwardNumber)
10345  {
10346  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10347  ForwardSet = true;
10348  }
10349  if(Count == ReverseNumber)
10350  {
10351  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10352  ReverseSet = true;
10353  }
10354  }
10355  }
10356  }
10357  }
10358  }
10359  }
10360  }
10361  for(unsigned int x = 0; x < TrackVector.size(); x++)
10362  {
10363  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10364  {
10366  }
10367  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10368  {
10370  }
10371  }
10372  Utilities->CallLogPop(639);
10373 }
10374 
10375 // ---------------------------------------------------------------------------
10376 
10377 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10378 {
10379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10380  TTrackElement Next;
10381 
10383  while(ReturnNextInactiveTrackElement(1, Next))
10384  {
10385  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10386  {
10387  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10388  // need striped graphics
10389  {
10390  if(Next.SpeedTag == 76)
10391  {
10392  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10393  }
10394  else if(Next.SpeedTag == 77)
10395  {
10396  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10397  }
10398  else if(Next.SpeedTag == 78)
10399  {
10400  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10401  }
10402  else if(Next.SpeedTag == 79)
10403  {
10404  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10405  }
10406  else if(Next.SpeedTag == 96)
10407  {
10408  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10409  }
10410  else if(Next.SpeedTag == 131)
10411  {
10412  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10413  }
10414  }
10415  else
10416  {
10417  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10418  }
10419  }
10420  }
10421 
10422  NextTrackElementPtr = TrackVector.begin();
10423  while(ReturnNextTrackElement(1, Next))
10424  {
10425  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10426  {
10427  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10428  {
10429  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10430  {
10431  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10432  }
10433  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10434  {
10435  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10436  }
10437  }
10438  else
10439  {
10440  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10441  }
10442  }
10443  }
10444  Disp->Update();
10445  Utilities->CallLogPop(640);
10446 }
10447 
10448 // ---------------------------------------------------------------------------
10449 
10450 void TTrack::PlotSmallRedGap(int Caller)
10451 {
10452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10454  Utilities->CallLogPop(1346);
10455 }
10456 
10457 // ---------------------------------------------------------------------------
10458 
10459 void TTrack::TrackClear(int Caller)
10460 {
10461  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10462  TrackVector.clear();
10463  InactiveTrackVector.clear();
10464  TrackMap.clear();
10466  if(TextHandler->TextVector.size() == 0)
10467  {
10468  Display->DisplayOffsetH = 0;
10469  Display->DisplayOffsetV = 0;
10476  HLocMin = 2000000000;
10477  HLocMax = -2000000000;
10478  VLocMin = 2000000000;
10479  VLocMax = -2000000000;
10480  }
10481  else
10482  {
10483  CalcHLocMinEtc(4);
10484  }
10485  Utilities->CallLogPop(1347);
10486 }
10487 
10488 // ---------------------------------------------------------------------------
10489 
10490 void TTrack::CalcHLocMinEtc(int Caller)
10491 {
10492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10493  HLocMin = 2000000000;
10494  VLocMin = 2000000000;
10495  HLocMax = -2000000000;
10496  VLocMax = -2000000000;
10497  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10498  {
10499  if(TrackElementAt(1385, x).SpeedTag == 0)
10500  {
10501  continue; // skip erase elements or would interfere with Min & Max values
10502  }
10503  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10504  {
10505  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10506  }
10507  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10508  {
10509  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10510  }
10511  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10512  {
10513  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10514  }
10515  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10516  {
10517  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10518  }
10519  }
10520  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10521  {
10522  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10523  {
10524  continue; // shouldn't be any inactive erase elements but include anyway
10525  }
10526  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10527  {
10528  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10529  }
10530  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10531  {
10532  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10533  }
10534  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10535  {
10536  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10537  }
10538  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10539  {
10540  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10541  }
10542  }
10543  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10544  {
10545 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10546  will fail as x will exceed the maximum value
10547  if(TextHandler->TextPtrAt(, x)->TextString == "")
10548  {
10549  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10550  }
10551 */
10552  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10553  if((TextH / 16) - 1 < HLocMin)
10554  {
10555  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10556  }
10557  if((TextH / 16) + 1 > HLocMax)
10558  {
10559  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10560  }
10561  if((TextV / 16) - 1 < VLocMin)
10562  {
10563  VLocMin = (TextV / 16) - 1;
10564  }
10565  if((TextV / 16) + 1 > VLocMax)
10566  {
10567  VLocMax = (TextV / 16) + 1;
10568  }
10569  }
10570  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10571  {
10572  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10573  {
10574  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10575  }
10576  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10577  {
10578  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10579  }
10580  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10581  {
10582  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10583  }
10584  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10585  {
10586  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10587  }
10588  }
10589 
10590  Utilities->CallLogPop(641);
10591 }
10592 
10593 // ---------------------------------------------------------------------------
10594 
10595 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10596  bool &UserGraphicFoundFlag)
10597 {
10598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10599  TUserGraphicVector::iterator UserGraphicPtr;
10600 
10601  UserGraphicFoundFlag = false;
10602  if(!UserGraphicVector.empty())
10603  {
10604  int x = UserGraphicVector.size();
10605  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10606  {
10607  x--;
10608  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10609  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10610  {
10611  UserGraphicItem = x;
10612  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10613  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10614  UserGraphicFoundFlag = true;
10615  Utilities->CallLogPop(2177);
10616  return;
10617  } // if ....
10618 
10619  } // for UserGraphicPtr...
10620  } // if !UserGraphicVector...
10621 
10622  Utilities->CallLogPop(2197);
10623 }
10624 
10625 // ---------------------------------------------------------------------------
10626 
10628 {
10629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10630  TrackElement.LogTrack(11));
10631  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10632  int SpeedTag = TrackElement.SpeedTag;
10633 
10634  if(SpeedTag < 1)
10635  {
10636  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10637  }
10638  switch(SpeedTag)
10639  {
10640  case 76: // t platform
10641  GraphicOutput = RailGraphics->gl76Striped;
10642  break;
10643 
10644  case 77: // h platform
10645  GraphicOutput = RailGraphics->bm77Striped;
10646  break;
10647 
10648  case 78: // v platform
10649  GraphicOutput = RailGraphics->bm78Striped;
10650  break;
10651 
10652  case 79: // r platform
10653  GraphicOutput = RailGraphics->gl79Striped;
10654  break;
10655 
10656  case 96: // concourse
10657  GraphicOutput = RailGraphics->ConcourseStriped;
10658  break;
10659 
10660  case 129: // v footbridge
10661  GraphicOutput = RailGraphics->gl129Striped;
10662  break;
10663 
10664  case 130: // h footbridge
10665  GraphicOutput = RailGraphics->gl130Striped;
10666  break;
10667 
10668  case 131: // non-station named loc
10669  GraphicOutput = RailGraphics->bmNameStriped;
10670  break;
10671 
10672  case 145: // v u'pass
10673  GraphicOutput = RailGraphics->gl145Striped;
10674  break;
10675 
10676  case 146: // h u'pass
10677  GraphicOutput = RailGraphics->gl146Striped;
10678  break;
10679 
10680  default:
10681  GraphicOutput = TrackElement.GraphicPtr;
10682  break;
10683  }
10684  Utilities->CallLogPop(642);
10685  return(GraphicOutput);
10686 }
10687 
10688 // ---------------------------------------------------------------------------
10689 
10691 {
10692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10693  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10694  {
10695 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10696  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10697  }
10698  Utilities->CallLogPop(643);
10699  return(TrackVector.at(At));
10700 }
10701 
10702 // ---------------------------------------------------------------------------
10703 
10705 {
10706  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10707  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10708  {
10709  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10710  " in InactiveTrackElementAt");
10711  }
10712  Utilities->CallLogPop(644);
10713  return(InactiveTrackVector.at(At));
10714 }
10715 
10716 // ---------------------------------------------------------------------------
10717 
10718 bool TTrack::BlankElementAt(int Caller, int At) const
10719 {
10720  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10721  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10722  {
10723  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10724  }
10725  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10726  {
10727  Utilities->CallLogPop(645);
10728  return(true);
10729  }
10730  else
10731  {
10732  Utilities->CallLogPop(646);
10733  return(false);
10734  }
10735 }
10736 
10737 // ---------------------------------------------------------------------------
10738 
10739 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10740 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10741  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10742  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10743  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10744  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10745 */
10746 {
10747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10748  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10749  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10750  TLocationNameMultiMapIterator SNIterator;
10751  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10752 
10753  if(SNRange.first == SNRange.second)
10754  {
10755  Utilities->CallLogPop(972);
10756  return(false); // should have been caught earlier but include for completeness
10757  }
10758  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10759  {
10760  if(SNIterator->second < 0)
10761  {
10762  continue; // exclude footcrossings
10763  }
10764  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10765  if(InactiveElement.TrackType == Concourse)
10766  {
10767  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10768  }
10769  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10770  {
10771  continue; // only interested in locations where ActiveTrackElementName may be set
10772  }
10773  THVPair HVPair;
10774  HVPair.first = InactiveElement.HLoc;
10775  HVPair.second = InactiveElement.VLoc;
10776  if(TrackMap.find(HVPair) == TrackMap.end())
10777  {
10778  throw Exception
10779  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10780  }
10781  int TVPos = TrackMap.find(HVPair)->second;
10782  FirstNamedElement = TrackElementAt(560, TVPos);
10783  // first check linked on both sides, skip the check if not
10784  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10785  {
10786  continue;
10787  }
10788  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10789  // ActiveTrackElementNames are points and excluding trailing connections for points
10790  FirstNamedExitPos = 0;
10791  {
10792  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10793  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10794  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10795  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10796  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10797  {
10798  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10799  {
10800  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10801  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10802  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10803  // success, now check FirstNamedElement link not trailing points & if so all OK
10804  {
10805  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10806  {
10807  Utilities->CallLogPop(1002);
10808  return(true);
10809  }
10810  }
10811  }
10812  }
10813  }
10814  // failed, try link 1
10815  FirstNamedExitPos = 1;
10816  {
10817  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10818  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10819  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10820  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10821  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10822  {
10823  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10824  {
10825  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10826  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10827  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10828  // success, now check FirstNamedElement link not trailing points & if so all OK
10829  {
10830  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10831  {
10832  Utilities->CallLogPop(1003);
10833  return(true);
10834  }
10835  }
10836  }
10837  }
10838  }
10839  }
10840  Utilities->CallLogPop(1004);
10841  return(false);
10842 }
10843 
10844 // ---------------------------------------------------------------------------
10845 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10846  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10847 // for success need two linked named location elements, so that one element of each train can be at the location
10848 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10849 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10850 // the two trains will occupy these 4 elements
10851 // All are track vector positions, all but the input being references and set within the function.
10852 {
10853 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10854  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10855  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10856  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10857  splitting.
10858 */
10859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10860  AnsiString(FirstNamedElementPos));
10861  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10862  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10863 
10864  SecondNamedElementPos = -1;
10865  FirstNamedLinkedElementPos = -1;
10866  SecondNamedLinkedElementPos = -1;
10867  TLocationNameMultiMapIterator SNIterator;
10868  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10869 
10870  if(SNRange.first == SNRange.second) // i.e. location name not in map
10871  {
10872  Utilities->CallLogPop(1005);
10873  return(false); // should have been caught earlier but include for completeness
10874  }
10875  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10876  {
10877  if(SNIterator->second < 0)
10878  {
10879  continue; // exclude footcrossings
10880  }
10881  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10882  if(InactiveElement.TrackType == Concourse)
10883  {
10884  continue; // only interested in locations where ActiveTrackElementName may be set
10885  }
10886  THVPair HVPair;
10887  HVPair.first = InactiveElement.HLoc;
10888  HVPair.second = InactiveElement.VLoc;
10889  if(TrackMap.find(HVPair) == TrackMap.end())
10890  {
10891  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10892  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10893  // then it won't be found in TrackMap but it's still legitimate.
10894  {
10895  continue;
10896  }
10897  else // for anything else throw the error
10898  {
10899  throw Exception
10900  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10901  );
10902  }
10903  }
10904  int TVPos = TrackMap.find(HVPair)->second;
10905  if(TVPos != FirstNamedElementPos)
10906  {
10907  continue; // looking for an exact match
10908  }
10909  FirstNamedElement = TrackElementAt(567, TVPos);
10910  // first check linked on both sides, skip the check if not
10911  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10912  {
10913  continue;
10914  }
10915  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10916  // ActiveTrackElementNames are points and excluding trailing connections for points
10917  FirstNamedExitPos = 0;
10918  {
10919  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10920  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10921  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10922  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10923  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10924  {
10925  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10926  {
10927  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10928  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10929  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10930  // success, now check FirstNamedElement link not trailing points & if so all OK
10931  {
10932  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10933  {
10934  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10935  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10936  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10937  Utilities->CallLogPop(1006);
10938  return(true);
10939  }
10940  }
10941  }
10942  }
10943  }
10944  // failed, try link 1
10945  FirstNamedExitPos = 1;
10946  {
10947  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10948  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10949  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10950  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10951  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10952  {
10953  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10954  {
10955  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10956  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10957  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10958  // success, now check FirstNamedElement link not trailing points & if so all OK
10959  {
10960  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10961  {
10962  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10963  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10964  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10965  Utilities->CallLogPop(1007);
10966  return(true);
10967  }
10968  }
10969  }
10970  }
10971  }
10972  }
10973  Utilities->CallLogPop(1008);
10974  return(false);
10975 }
10976 
10977 // ---------------------------------------------------------------------------
10978 
10979 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10980 {
10981  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10982  TLocationNameMultiMapIterator SNIterator;
10983  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10984 
10985  if(SNRange.first != SNRange.second)
10986  {
10987  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10988  {
10989  if(SNIterator->second < 0)
10990  {
10991  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10992  }
10993  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10994  SNIterator->second).TrackType == NamedNonStationLocation))
10995  {
10996  Utilities->CallLogPop(1121);
10997  return(true);
10998  }
10999  }
11000  }
11001  Utilities->CallLogPop(848);
11002  return(false);
11003 }
11004 
11005 // ---------------------------------------------------------------------------
11006 
11007 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11008 {
11009 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11010  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11011  "," + AnsiString(SpeedTag));
11012  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11013  {
11014  Utilities->CallLogPop(949);
11015  return(false);
11016  }
11017  bool FoundFlag;
11018  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11019 
11020  if(!FoundFlag)
11021  {
11022  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11023  }
11024  TTrackElement IAElement;
11025 
11026  if(SpeedTag == 68) // top sig
11027  {
11028  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11029  {
11030  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11031  {
11032  IAElement = InactiveTrackElementAt(50, IMPair.first);
11033  }
11034  else
11035  {
11036  IAElement = InactiveTrackElementAt(51, IMPair.second);
11037  }
11038  if(IAElement.LocationName == "")
11039  {
11040 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11041  SignalPlatformGraphic = RailGraphics->gl76Striped;
11042  }
11043  else
11044  {
11045 // SignalPlatformGraphic = RailGraphics->Plat68;
11046  SignalPlatformGraphic = RailGraphics->gl76;
11047  }
11048  Utilities->CallLogPop(950);
11049  return(true);
11050  }
11051  }
11052  else if(SpeedTag == 69) // bot sig
11053  {
11054  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11055  {
11056  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11057  {
11058  IAElement = InactiveTrackElementAt(77, IMPair.first);
11059  }
11060  else
11061  {
11062  IAElement = InactiveTrackElementAt(78, IMPair.second);
11063  }
11064  if(IAElement.LocationName == "")
11065  {
11066 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11067  SignalPlatformGraphic = RailGraphics->bm77Striped;
11068  }
11069  else
11070  {
11071 // SignalPlatformGraphic = RailGraphics->Plat69;
11072  SignalPlatformGraphic = RailGraphics->bm77;
11073  }
11074  Utilities->CallLogPop(951);
11075  return(true);
11076  }
11077  }
11078  else if(SpeedTag == 70) // left sig
11079  {
11080  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11081  {
11082  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11083  {
11084  IAElement = InactiveTrackElementAt(55, IMPair.first);
11085  }
11086  else
11087  {
11088  IAElement = InactiveTrackElementAt(82, IMPair.second);
11089  }
11090  if(IAElement.LocationName == "")
11091  {
11092 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11093  SignalPlatformGraphic = RailGraphics->bm78Striped;
11094  }
11095  else
11096  {
11097 // SignalPlatformGraphic = RailGraphics->Plat70;
11098  SignalPlatformGraphic = RailGraphics->bm78;
11099  }
11100  Utilities->CallLogPop(952);
11101  return(true);
11102  }
11103  }
11104  else if(SpeedTag == 71) // right sig
11105  {
11106  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11107  {
11108  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11109  {
11110  IAElement = InactiveTrackElementAt(85, IMPair.first);
11111  }
11112  else
11113  {
11114  IAElement = InactiveTrackElementAt(86, IMPair.second);
11115  }
11116  if(IAElement.LocationName == "")
11117  {
11118 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11119  SignalPlatformGraphic = RailGraphics->gl79Striped;
11120  }
11121  else
11122  {
11123 // SignalPlatformGraphic = RailGraphics->Plat71;
11124  SignalPlatformGraphic = RailGraphics->gl79;
11125  }
11126  Utilities->CallLogPop(953);
11127  return(true);
11128  }
11129  }
11130  Utilities->CallLogPop(954);
11131  return(false);
11132 }
11133 
11134 // ---------------------------------------------------------------------------
11135 
11136 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
11137 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
11138 // false if not, if NextPos == -1, or if only own train on the track
11139 {
11140  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
11141  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
11142  if(NextEntryPos < 0)
11143  {
11144  Utilities->CallLogPop(1348);
11145  return(false);
11146  }
11147  TTrackElement TrackElement = TrackElementAt(713, NextPos);
11148 
11149  if(TrackElement.TrackType != Bridge)
11150  {
11151  Utilities->CallLogPop(1349);
11152  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11153  }
11154 // bridge if reach here
11155  if(NextEntryPos > 1)
11156  {
11157  Utilities->CallLogPop(1350);
11158  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11159  }
11160  else
11161  {
11162  Utilities->CallLogPop(1351);
11163  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11164  }
11165 }
11166 
11167 // ---------------------------------------------------------------------------
11168 
11170 {
11171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11172  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11173  {
11174  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11175  }
11176  Utilities->CallLogPop(1483);
11177  return(SelectVector.at(At));
11178 }
11179 
11180 // ---------------------------------------------------------------------------
11181 
11182 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11183 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11184 {
11185  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11186  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11187  bool FoundFlag = false;
11188  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11189  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11190 
11191  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11192  Utilities->CallLogPop(1538);
11193  return(FoundFlag);
11194 }
11195 
11196 // ---------------------------------------------------------------------------
11197 
11198 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11199 {
11200 // return true if find an inactive element called 'Name'
11201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11202  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11203  bool FoundFlag = false;
11204 
11205  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11206  {
11207  if(InactiveTrackElementAt(158, x).LocationName == Name)
11208  {
11209  FoundFlag = true;
11210  int V = InactiveTrackElementAt(159, x).VLoc;
11211  int H = InactiveTrackElementAt(160, x).HLoc;
11212  if(V > VLocHi)
11213  {
11214  VLocHi = V;
11215  }
11216  if(V < VLocLo)
11217  {
11218  VLocLo = V;
11219  }
11220  if(H < HLoc)
11221  {
11222  HLoc = H;
11223  }
11224  }
11225  }
11226  if(FoundFlag)
11227  {
11228  VPosHi = 16 * VLocHi;
11229  VPosLo = 16 * VLocLo;
11230  HPos = 16 * HLoc;
11231  Utilities->CallLogPop(1562);
11232  return(true);
11233  }
11234  else
11235  {
11236  Utilities->CallLogPop(1563);
11237  return(false);
11238  }
11239 }
11240 
11241 // ---------------------------------------------------------------------------
11242 
11243 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11244 {
11245 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11246 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11248  AnsiString(EndTVPosition));
11249  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11250  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11251 
11252 // get H & V values for the element adjacent to Link[0] & Link[1]
11253  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11254  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11255  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11256  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11257 
11258 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11259  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11260  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11261  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11262  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11263 
11264  if(Link0Squares <= Link1Squares)
11265  {
11266  Utilities->CallLogPop(1851);
11267  return(0);
11268  }
11269  else
11270  {
11271  Utilities->CallLogPop(1852);
11272  return(1);
11273  }
11274 }
11275 
11276 // ---------------------------------------------------------------------------
11277 
11278 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11279 {
11280  // element can be points or any other type
11281  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11282  AnsiString(LinkPos));
11283  Derail = false;
11284  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11285 
11286  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11287  {
11288  if(TE.Attribute == 0)
11289  {
11290  Utilities->CallLogPop(663);
11291  return(1); // Att == 0 & ExitPos == 1 represent straight
11292  }
11293  else
11294  {
11295  Utilities->CallLogPop(664);
11296  return(3); // Att == 1 & ExitPos == 3 represent diverging
11297  }
11298  }
11299  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11300  {
11301  if((LinkPos == 1) && (TE.Attribute == 0))
11302  {
11303  Utilities->CallLogPop(665);
11304  return(0); // Att == 0 represents straight
11305  }
11306  else if(LinkPos == 1)
11307  {
11308  Derail = true;
11309  Utilities->CallLogPop(666);
11310  return(0);
11311  }
11312  else if((LinkPos == 3) && (TE.Attribute == 1))
11313  {
11314  Utilities->CallLogPop(667);
11315  return(0);
11316  }
11317  else if(LinkPos == 3)
11318  {
11319  Derail = true;
11320  Utilities->CallLogPop(668);
11321  return(0);
11322  }
11323  }
11324  else if(LinkPos == 0)
11325  {
11326  Utilities->CallLogPop(669);
11327  return(1);
11328  }
11329  else if(LinkPos == 1)
11330  {
11331  Utilities->CallLogPop(670);
11332  return(0);
11333  }
11334  else if(LinkPos == 2)
11335  {
11336  Utilities->CallLogPop(671);
11337  return(3);
11338  }
11339  else if(LinkPos == 3)
11340  {
11341  Utilities->CallLogPop(672);
11342  return(2);
11343  }
11344  throw Exception("Error, failure in GetExitPos"); // should never reach here
11345 }
11346 
11347 // ----------------------------------------------------------------------------
11348 
11350 {
11351  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11352  LCVector.clear();
11353  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11354  {
11355  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11356  {
11357  LCVector.push_back(x);
11358  }
11359  }
11360  Utilities->CallLogPop(1931);
11361  return;
11362 }
11363 
11364 // ---------------------------------------------------------------------------
11365 
11366 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11367 /*
11368  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11369  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11370  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11371  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11372 */
11373 {
11374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11375  AnsiString(Link));
11376  bool FoundFlag;
11377 
11378  TrainID = -1;
11379  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11380 
11381  if(!FoundFlag)
11382  {
11383  Utilities->CallLogPop(2001);
11384  return(false);
11385  }
11386  TTrackElement TE = TrackElementAt(882, VecPos);
11387 
11388  TrainID = TE.TrainIDOnElement;
11389  if(TE.TrackType == Bridge)
11390  {
11391  if(TE.TrainIDOnElement > -1)
11392  {
11393  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11394  {
11396  }
11397  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11398  {
11400  }
11401  else
11402  {
11403  TrainID = -1; // shouldn't ever reach here but be safe
11404  }
11405  }
11406  }
11407  if(TrainID == -1)
11408  {
11409  Utilities->CallLogPop(2002);
11410  return(false);
11411  }
11412 // now get the train
11413  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11414 
11415  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11416  {
11417  Utilities->CallLogPop(2003);
11418  return(true);
11419  }
11420  TrainID = -1;
11421  Utilities->CallLogPop(2004);
11422  return(false);
11423 }
11424 
11425 // ---------------------------------------------------------------------------
11426 
11427 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11428 /* New at v1.2.0
11429  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11430  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11431  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11432  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11433  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11434  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11435  Each of these is examined in turn for each route element in the relevant position.
11436 */
11437 {
11438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11439  "," + AnsiString(DiagonalLinkNumber));
11440  TrainID = -1;
11441  TPrefDirElement TempPrefDirElement;
11442  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11443 
11444  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11445  {
11446  Utilities->CallLogPop(2027);
11447  return(true);
11448  }
11449  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11450  {
11451  Utilities->CallLogPop(2028);
11452  return(true);
11453  }
11454  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11455  {
11456  Utilities->CallLogPop(2029);
11457  return(true);
11458  }
11459  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11460  {
11461  Utilities->CallLogPop(2030);
11462  return(true);
11463  }
11464  Utilities->CallLogPop(2031);
11465  return(false);
11466 }
11467 
11468 // ---------------------------------------------------------------------------
11469 
11470 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11471 {
11472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11473  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11474  TUserGraphicItem UGI;
11475  AnsiString JustFileName = "";
11476 
11477  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11478  {
11479  UGI = UserGraphicVectorAt(17, x);
11480  int LastDelim = UGI.FileName.LastDelimiter('\\');
11481  if(LastDelim == 0) // can't find it so skip this item
11482  {
11483  continue;
11484  }
11485  else
11486  {
11487  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11488  }
11489  Utilities->SaveFileString(VecFile, JustFileName);
11490  Utilities->SaveFileInt(VecFile, UGI.HPos);
11491  Utilities->SaveFileInt(VecFile, UGI.VPos);
11492  }
11493  Utilities->CallLogPop(2178);
11494 }
11495 
11496 // ---------------------------------------------------------------------------
11497 
11498 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11499 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11500 {
11501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11502  int NumPlats = 0;
11503  TTrackElement TempElement;
11504  int TempInt;
11505 
11506  typedef std::list<int> TNamePosList;
11507  TNamePosList NamePosList;
11508  typedef TNamePosList::iterator TNPLIt;
11509  TNPLIt NPLIt;
11510  typedef std::list<int> TOnePlatList;
11511  TOnePlatList OnePlatList;
11512  typedef TOnePlatList::iterator TOPLIt;
11513  TOPLIt OPLIt;
11514 
11515  NamePosList.clear();
11516  OnePlatList.clear();
11517  for(unsigned int x = 0; x < TrackVector.size(); x++)
11518  {
11519  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11520  {
11521  NamePosList.push_back(x);
11522  }
11523  }
11524  //NamePosList complete
11525 
11526  if(!NamePosList.empty()) //first value for the loop examination
11527  {
11528  OnePlatList.push_back(NamePosList.back());
11529  NamePosList.pop_back(); //erase from NPV as done with it here
11530  }
11531  while(!OnePlatList.empty()) //loop to examine all linked elements
11532  {
11533  TempInt = OnePlatList.front();
11534  TempElement = TrackElementAt(989, TempInt);
11535 
11536  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11537  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11538  {
11539  OnePlatList.push_back(TempElement.Conn[0]);
11540  NamePosList.erase(NPLIt);
11541  }
11542  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11543  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11544  {
11545  OnePlatList.push_back(TempElement.Conn[1]);
11546  NamePosList.erase(NPLIt);
11547  }
11548  //here when loaded any connecting links into OnePlatList, so can erase the front element
11549  OnePlatList.erase(OnePlatList.begin());
11550  if(OnePlatList.empty())
11551  {
11552  NumPlats++; //finished with current linked elements so can increment NumPlats
11553  if(!NamePosList.empty())
11554  {
11555  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11556  NamePosList.pop_back(); //erase from NPV as done with it there
11557  }
11558  }
11559  }
11560  Utilities->CallLogPop(2218);
11561  return(NumPlats);
11562 }
11563 
11564 // ---------------------------------------------------------------------------
11565 
11566 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11567 {//repair Signals pointed to by FPVIt
11568  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
11569  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
11570  if(TE.TrackType != SignalPost)
11571  {
11572  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
11573  }
11574  if(!TE.Failed)
11575  {
11576  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
11577  }
11578  TE.Failed = false;
11579  //set to correct aspect
11580  int RouteNumber;
11581  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
11582  { // 0 for LinkPos ok as a signal so only one track
11583  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
11584  }
11585  //erase from vector
11586  Track->FailedSignalsVector.erase(FPVIt);
11587 
11588  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11589  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11590  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
11591  AllRoutes->RebuildRailwayFlag = true;
11592  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
11593  Utilities->CallLogPop(2519);
11594 }
11595 
11596 // ---------------------------------------------------------------------------
11597 
11598 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11599 {//repair points pointed to by FPVIt
11600  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
11601  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
11602  if(TE.TrackType != Points)
11603  {
11604  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
11605  }
11606  if(!TE.Failed)
11607  {
11608  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
11609  }
11610  TE.Failed = false;
11615  //erase from vector
11616  Track->FailedPointsVector.erase(FPVIt);
11617 
11618  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11619  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11620  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
11621  AllRoutes->RebuildRailwayFlag = true;
11622  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11623  Utilities->CallLogPop(2518);
11624 }
11625 
11626 // ---------------------------------------------------------------------------
11627 
11628 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11629 {//repair TSR pointed to by FPVIt
11630  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
11631  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
11632  if(TE.TrackType != Simple)
11633  {
11634  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
11635  }
11636  if(!TE.Failed)
11637  {
11638  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
11639  }
11640  TE.Failed = false;
11643  //erase from vector
11644  Track->TSRVector.erase(FPVIt);
11645 
11646  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11647  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11648  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
11649  AllRoutes->RebuildRailwayFlag = true;
11650  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11651  Utilities->CallLogPop(2520);
11652 }
11653 
11654 // ---------------------------------------------------------------------------
11655 
11657 {
11658  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
11659  SimpleVector.clear();
11660  for(unsigned int x = 0; x < TrackVector.size(); x++)
11661  {
11662  if(TrackElementAt(1517, x).TrackType == Simple)
11663  {
11664  SimpleVector.push_back(int(x));
11665  }
11666  }
11667  Utilities->CallLogPop(2521);
11668 }
11669 
11670 // ---------------------------------------------------------------------------
11671 // UserGraphic, PrefDir & Route functions
11672 // ---------------------------------------------------------------------------
11673 
11675 {
11676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11677  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11678  {
11679  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11680  }
11681  Utilities->CallLogPop(2194);
11682  return(UserGraphicVector.at(At));
11683 }
11684 
11685 // ---------------------------------------------------------------------------
11686 
11687 int TOnePrefDir::LastElementNumber(int Caller) const
11688 {
11689  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11690  int RetVal = PrefDirVector.size() - 1;
11691 
11692  if(RetVal < 0)
11693  {
11694  throw Exception("Return value negative in call to LastElementNumber");
11695  }
11696  Utilities->CallLogPop(114);
11697  return(RetVal);
11698 }
11699 
11700 // ---------------------------------------------------------------------------
11702 {
11703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11704  if(PrefDirVector.empty())
11705  {
11706  throw Exception("PrefDirVector empty in call to LastElementPtr");
11707  }
11708  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11709 
11710  Utilities->CallLogPop(115);
11711  return(RetIT);
11712 }
11713 
11714 // ---------------------------------------------------------------------------
11716 {
11717  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11718  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11719  {
11720  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11721  }
11722  Utilities->CallLogPop(116);
11723  return(PrefDirVector.at(At));
11724 }
11725 
11726 // ---------------------------------------------------------------------------
11728 {
11729  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11730  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11731  {
11732  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11733  " in GetModifiablePrefDirElementAt");
11734  }
11735  Utilities->CallLogPop(117);
11736  return(PrefDirVector.at(At));
11737 }
11738 
11739 // ---------------------------------------------------------------------------
11741 {
11742  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11743  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11744  {
11745  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11746  }
11747  Utilities->CallLogPop(118);
11748  return(SearchVector.at(At));
11749 }
11750 
11751 // ---------------------------------------------------------------------------
11753 {
11754  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11755  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11756  {
11757  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11758  }
11759  Utilities->CallLogPop(119);
11760  return(SearchVector.at(At));
11761 }
11762 
11763 // ---------------------------------------------------------------------------
11764 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11765 /*
11766  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11767  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11768  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11769  set in later functions.
11770 */
11771 {
11772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11773  ClearPrefDir();
11774  int TrackVectorPosition;
11775  TTrackElement TrackElement;
11776 
11777  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11778  {
11779  Utilities->CallLogPop(126);
11780  return(false);
11781  }
11782 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11783  if(TrackElement.TrackType == Points)
11784  {
11785  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11786  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11787  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11788  //best to prevent it to avoid problems
11789  Utilities->CallLogPop(127);
11790  return false;
11791  }
11792 */
11793  TPrefDirElement PrefDirElement(TrackElement);
11794 
11795  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11796  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11797  StorePrefDirElement(1, PrefDirElement); // enter first element
11798 // Note that ELink not set even if a buffer or continuation - these set in
11799 // ConvertPrefDirSearchVector after 2nd element added
11800 
11801  Utilities->CallLogPop(128);
11802  return(true);
11803 }
11804 
11805 // ---------------------------------------------------------------------------
11806 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11807 
11808 /*
11809  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11810  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
11811  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11812  with setting the PrefDir vector, & return true.
11813  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11814  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
11815  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11816  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11817  ConvertPrefDirSearchVector to set PrefDirVector.
11818  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11819  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11820  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11821 */
11822 
11823 {
11824  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11825  FinishElement = false;
11826  int TrackVectorPosition;
11827 
11828  TotalSearchCount = 0;
11829  TTrackElement TrackElement, TempTrackElement;
11830 
11831  if(PrefDirVector.size() == 0)
11832  {
11833  Utilities->CallLogPop(129);
11834  return(false);
11835  }
11836  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11837  {
11838  Utilities->CallLogPop(130);
11839  return(false);
11840  }
11841 // set the search limits using the last stored element in PrefDirVector as the start point
11842 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11843 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11844 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11845 
11846  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11847 
11848  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11849  {
11850  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11851  SearchLimitHighH = TrackElement.HLoc + 15;
11852  }
11853  else
11854  {
11855  SearchLimitLowH = TrackElement.HLoc - 15;
11856  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11857  }
11858  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11859  {
11860  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11861  SearchLimitHighV = TrackElement.VLoc + 15;
11862  }
11863  else
11864  {
11865  SearchLimitLowV = TrackElement.VLoc - 15;
11866  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11867  }
11868 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11869  check & TotalSearchCounts check
11870  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11871  {
11872  ShowMessage("Unable to reach the selected element - too far ahead");
11873  Utilities->CallLogPop(1692);
11874  return false;
11875  }
11876 */
11877 // get last PrefDir element
11878  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11879  {
11880  // check if TrackElement adjacent to any of the 4 XLinkPos'
11881  for(int x = 0; x < 4; x++)
11882  {
11883  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11884  {
11885  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11886  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11887  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11888  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11889  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11890  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11891  // shouldn't ever get it in a serious railway though.
11892 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11893  }
11894  }
11895  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11896  {
11897  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11898  SearchVector.clear(); // use this & convert to set all PrefDir element values
11899  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11900  {
11902  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11903  {
11904  FinishElement = true;
11905  }
11906  Utilities->CallLogPop(131);
11907  return(true);
11908  }
11909  } // not an adjacent element
11910 
11911  // now check each of the 4 possible XLinkPos values
11912  for(int x = 0; x < 4; x++)
11913  {
11914  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11915  {
11916  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11917  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11918  SearchVector.clear();
11919  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11920  {
11922  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11923  {
11924  FinishElement = true;
11925  }
11926  Utilities->CallLogPop(132);
11927  return(true);
11928  }
11929  }
11930  } // here if checked all possible exits without success
11931  ShowMessage(
11932  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11933  Utilities->CallLogPop(133);
11934  return(false);
11935  }
11936 // dealt above with LastPrefDirElement being the start element (which can be points)
11937 
11938  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11939  .ELinkPos] == Lead)) // leading point
11940  {
11941  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11942  {
11943  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11944  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11945  // can't be buffers or gap if points
11946  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11947  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11948  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11949  SearchVector.clear();
11950  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11951  {
11953  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11954  {
11955  FinishElement = true;
11956  }
11957  Utilities->CallLogPop(134);
11958  return(true);
11959  }
11960  }
11961  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11962  {
11963  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11964  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11965  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11966  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11967  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11968  SearchVector.clear();
11969  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11970  {
11972  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11973  {
11974  FinishElement = true;
11975  }
11976  Utilities->CallLogPop(135);
11977  return(true);
11978  }
11979  }
11980 // above dealt with immediate finds for leading point,
11981 // now deal with ordinary searches for leading point
11982  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11983  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11984  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11985  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11986  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11987  SearchVector.clear();
11988  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11989  {
11991  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11992  {
11993  FinishElement = true;
11994  }
11995  Utilities->CallLogPop(136);
11996  return(true);
11997  }
11998  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11999  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12000  // note that CheckCount already increased to allow for XLinkPos & XLink
12001  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12002  SearchVector.clear();
12003  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12004  {
12006  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12007  {
12008  FinishElement = true;
12009  }
12010  Utilities->CallLogPop(137);
12011  return(true);
12012  }
12013 // here if failed to find match for leading point
12014  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12015  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12016  ShowMessage(
12017  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12018  Utilities->CallLogPop(138);
12019  return(false);
12020  }
12021 // leading point fully dealt with above
12022 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12023 // separately as covered in ordinary search.
12024 
12025  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12026  SearchVector.clear();
12027 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12028  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12029  {
12031  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12032  {
12033  FinishElement = true;
12034  }
12035  Utilities->CallLogPop(139);
12036  return(true);
12037  }
12038  ShowMessage(
12039  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12040  Utilities->CallLogPop(140);
12041  return(false); // failed to find required element
12042 }
12043 
12044 // ---------------------------------------------------------------------------
12045 
12046 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12047 /*
12048  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12049  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12050  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12051  Keep a count of entries in SearchVector during the current function call, so that this number can be
12052  erased for an unproductive branch search.
12053  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12054  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12055  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12056  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12057  If not any of above, store element in searchvector, set the new current element values from the
12058  SearchElement, then go back to the while loop for the next step in the search.
12059 */
12060 {
12061  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12062  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12063  int VectorCount = 0;
12064 
12065  while(true)
12066  {
12067  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12068  {
12069  for(int x = 0; x < VectorCount; x++)
12070  {
12071  SearchVector.erase(SearchVector.end() - 1);
12072  }
12073  Utilities->CallLogPop(141);
12074  return(false);
12075  }
12076  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12077  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12078  TPrefDirElement SearchElement(NextTrackElement);
12079  SearchElement.TrackVectorPosition = NextPosition;
12080  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12081  SearchElement.ELinkPos = NextELinkPos;
12082  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12083  int NextXLinkPos;
12084  if(SearchElement.ELinkPos == 0)
12085  {
12086  NextXLinkPos = 1;
12087  }
12088  if(SearchElement.ELinkPos == 1)
12089  {
12090  NextXLinkPos = 0;
12091  }
12092  if(SearchElement.ELinkPos == 2)
12093  {
12094  NextXLinkPos = 3;
12095  }
12096  if(SearchElement.ELinkPos == 3)
12097  {
12098  NextXLinkPos = 2;
12099  }
12100  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12101  {
12102  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12103  // but may be buffers, continuation or gap
12104  SearchElement.XLinkPos = NextXLinkPos;
12105  }
12106 // can't set XLink or XLinkPos yet if the element is a leading point.
12107 // check if found it
12108  if(SearchElement.TrackVectorPosition == RequiredPosition)
12109  {
12110  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12111  VectorCount++; // not really needed but include for tidyness
12112  TotalSearchCount++;
12113  Utilities->CallLogPop(142);
12114  return(true);
12115  }
12116 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12117 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12118 // at a time - drop this
12119 /*
12120  if(PrefDirVector.size() > 200)
12121  {
12122  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12123  Utilities->CallLogPop(1419);
12124  return false;
12125  }
12126 */
12127 // check if a buffer or continuation
12128  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12129  {
12130  for(int x = 0; x < VectorCount; x++)
12131  {
12132  SearchVector.erase(SearchVector.end() - 1);
12133  }
12134  Utilities->CallLogPop(143);
12135  return(false);
12136  }
12137 // check if reached an earlier position on search PrefDir with same entry value
12138  for(unsigned int x = 0; x < SearchVector.size(); x++)
12139  {
12140  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12141  {
12142  for(int x = 0; x < VectorCount; x++)
12143  {
12144  SearchVector.erase(SearchVector.end() - 1);
12145  }
12146  Utilities->CallLogPop(144);
12147  return(false);
12148  }
12149  }
12150 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12151 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12152  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12153  {
12154  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12155  {
12156  for(int x = 0; x < VectorCount; x++)
12157  {
12158  SearchVector.erase(SearchVector.end() - 1);
12159  }
12160  Utilities->CallLogPop(1417);
12161  return(false);
12162  }
12163  }
12164 
12165 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12166 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12167 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12169  {
12170  for(int x = 0; x < VectorCount; x++)
12171  {
12172  SearchVector.erase(SearchVector.end() - 1);
12173  }
12174  Utilities->CallLogPop(1691);
12175  return(false);
12176  }
12177 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12178  if(SearchVector.size() > 150)
12179  {
12180  for(int x = 0; x < VectorCount; x++)
12181  {
12182  SearchVector.erase(SearchVector.end() - 1);
12183  }
12184  Utilities->CallLogPop(1418);
12185  return(false);
12186  }
12187 // check if reached a leading point
12188  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12189  {
12190 // push element with XLink set to position [1]
12191  SearchElement.XLink = SearchElement.Link[1];
12192  SearchElement.XLinkPos = 1;
12193  SearchVector.push_back(SearchElement);
12194  VectorCount++;
12195  TotalSearchCount++;
12196  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12197  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12198  // can't be used. NextTrackElement is the corresponding TTrackElement.
12199  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12200  {
12201  Utilities->CallLogPop(145);
12202  return(true);
12203  }
12204  else
12205  {
12206 // remove leading point with XLinkPos [1]
12207  SearchVector.erase(SearchVector.end() - 1);
12208  VectorCount--;
12209 // push element with XLink set to position [3]
12210  SearchElement.XLink = SearchElement.Link[3];
12211  SearchElement.XLinkPos = 3;
12212  SearchVector.push_back(SearchElement);
12213  VectorCount++;
12214  TotalSearchCount++;
12215 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12216  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12217  {
12218  Utilities->CallLogPop(146);
12219  return(true);
12220  }
12221  else
12222  {
12223  for(int x = 0; x < VectorCount; x++)
12224  {
12225  SearchVector.erase(SearchVector.end() - 1);
12226  }
12227  Utilities->CallLogPop(147);
12228  return(false);
12229  }
12230  }
12231  } // if leading point
12232 
12233 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12234 // ready for next element on PrefDir
12235  SearchVector.push_back(SearchElement);
12236  VectorCount++;
12237  TotalSearchCount++;
12238  XLinkPos = NextXLinkPos;
12239  CurrentTrackElement = SearchElement;
12240  } // while(true)
12241 }
12242 
12243 // ---------------------------------------------------------------------------
12244 
12246 /*
12247  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12248  for each element on the search PrefDir, though if the last element is a leading point
12249  then the final XLink won't be set.
12250  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12251  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12252  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12253 */
12254 {
12255  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12256  if(SearchVector.size() == 0)
12257  {
12258  throw Exception("Error, SearchVector empty");
12259  }
12260 // get first SearchElement in order to set last PrefDirelement
12261  TPrefDirElement SearchElement = SearchVector.at(0);
12262 
12263 // set last PrefDir element XLink & ELink values if not already set
12264 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12265  for(int x = 0; x < 4; x++)
12266  {
12267  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12268  {
12269  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12270  {
12271  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12272  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12273  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12274  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12275  }
12276  int ELinkPos;
12277  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12278  {
12279  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12280  }
12281  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12282  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12283  {
12284  ELinkPos = 0;
12285  }
12286  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12287  {
12288  ELinkPos = 3;
12289  }
12290  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12291  {
12292  ELinkPos = 2;
12293  }
12294  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12295  {
12296  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12297  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12298  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12299  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12300  }
12301  break; // no point going any further
12302  }
12303  }
12304 // set EXNumber for last PrefDir element, unless already set
12305 // won't be set if was first element or a leading point
12306  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12307  {
12308 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12309  int EXArray[32][2] = {
12310  {4,6},{2,8}, //horizontal & vertical
12311  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12312  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12313  {1,9},{3,7} //forward & reverse diagonals
12314 */
12315 
12316  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12317  {
12318  throw Exception("Error in EntryExitNumber 1");
12319  }
12320  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12321  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12322  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12323  }
12324 // Last PrefDir element now complete
12325 
12326 // construct remaining PrefDir elements from searchvector
12327  for(unsigned int x = 0; x < SearchVector.size(); x++)
12328  {
12329  SearchElement = SearchVector.at(x);
12330  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12331  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12332  PrefDirElement.ELink = SearchElement.ELink;
12333  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12334  PrefDirElement.XLink = SearchElement.XLink;
12335  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12336 // if XLink & XLinkPos not set don't account for them in CheckCount
12337  if(PrefDirElement.XLink == -1)
12338  {
12339  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12340  }
12341  // & TrackVectorPosition
12342  else
12343  {
12344  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12345  }
12346  // XLink, XLinkPos, TrackVectorPosition
12347 
12348 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12349  if(PrefDirElement.XLink != -1)
12350  {
12351  if(!(PrefDirElement.EntryExitNumber()))
12352  {
12353  throw Exception("Error in EntryExitNumber 2");
12354  }
12355  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12356  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12357  PrefDirElement.CheckCount++;
12358  // all values now incorporated if not a leading point
12359  }
12360 // store PrefDir element
12361  StorePrefDirElement(2, PrefDirElement);
12362  }
12363 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12364  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12365  {
12366  if(ValidatePrefDir(2))
12367  {
12368  ;
12369  } // error messages given within function
12370 
12371  }
12373 /* drop this, check dropped from search
12374  if(PrefDirVector.size() > 200)
12375  {
12376  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12377  }
12378 */
12379  Utilities->CallLogPop(148);
12380 }
12381 
12382 // ---------------------------------------------------------------------------
12383 
12384 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12385 /*
12386  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12387  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12388 */
12389 {
12390  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12391  LeadingPoints = false;
12392  if(PrefDirVector.empty())
12393  {
12394  Utilities->CallLogPop(1786);
12395  return(false); // should never be empty but allow for it for safety
12396  }
12397  if(PrefDirVector.size() == 1)
12398  {
12399  Utilities->CallLogPop(149);
12400  return(false); // can't end if only one element
12401  }
12402 /*
12403  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12404  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12405  {
12406  Utilities->CallLogPop(150);
12407  return true;
12408  }
12409 */
12410 // allow for anything but leading points
12411  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12412  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12413  {
12414  Utilities->CallLogPop(1776);
12415  return(true);
12416  }
12417  else
12418  {
12419  LeadingPoints = true;
12420  Utilities->CallLogPop(151);
12421  return(false);
12422  }
12423 }
12424 
12425 // ---------------------------------------------------------------------------
12426 
12428 /*
12429  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12430  and that every element is connected to the next element
12431 */
12432 {
12433  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12434  int Position;
12435  AnsiString ErrorString;
12436  bool Error = false;
12437 
12438  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12439  {
12440  if(PrefDirVector.at(x).HLoc == -2000000000)
12441  {
12442  Error = true;
12443  ErrorString = "HLoc";
12444  Position = x;
12445  }
12446  if(PrefDirVector.at(x).VLoc == -2000000000)
12447  {
12448  Error = true;
12449  ErrorString = "VLoc";
12450  Position = x;
12451  }
12452  if(PrefDirVector.at(x).ELink == -1)
12453  {
12454  Error = true;
12455  ErrorString = "ELink";
12456  Position = x;
12457  }
12458  if(PrefDirVector.at(x).ELinkPos == -1)
12459  {
12460  Error = true;
12461  ErrorString = "ELinkPos";
12462  Position = x;
12463  }
12464  if(PrefDirVector.at(x).XLink == -1)
12465  {
12466  Error = true;
12467  ErrorString = "XLink";
12468  Position = x;
12469  }
12470  if(PrefDirVector.at(x).XLinkPos == -1)
12471  {
12472  Error = true;
12473  ErrorString = "XLinkPos";
12474  Position = x;
12475  }
12476  if(PrefDirVector.at(x).SpeedTag == 0)
12477  {
12478  Error = true;
12479  ErrorString = "Tag";
12480  Position = x;
12481  }
12482  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12483  {
12484  Error = true;
12485  ErrorString = "TrackVectorPosition";
12486  Position = x;
12487  }
12488  if(PrefDirVector.at(x).EXNumber == -1)
12489  {
12490  Error = true;
12491  ErrorString = "EXNumber";
12492  Position = x;
12493  }
12494  if(PrefDirVector.at(x).CheckCount != 9)
12495  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12496  {
12497  Error = true;
12498  ErrorString = "CheckCount";
12499  Position = x;
12500  }
12501 // extra checks
12502  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12503  {
12504  Error = true;
12505  ErrorString = "EntryGraphicPtr";
12506  Position = x;
12507  }
12508  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12509  {
12510  Error = true;
12511  ErrorString = "EntryDirectionGraphicPtr";
12512  Position = x;
12513  }
12514 // end of extra checks
12515  if(x > 0)
12516  {
12517  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12518  {
12519  Error = true;
12520  ErrorString = "Last XLink not connected to this element";
12521  Position = x;
12522  }
12523  }
12524  }
12525  if(Error)
12526  {
12527  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12528  }
12529  else
12530  {
12531  Utilities->CallLogPop(153);
12532  return(true);
12533  }
12534 }
12535 
12536 // ---------------------------------------------------------------------------
12537 
12538 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12539 /*
12540  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12541  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12542  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12543  or a leading point.
12544 */
12545 {
12546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12547  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12548  {
12549  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12550  {
12551  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12552  {
12553  ErasePrefDirElementAt(1, PrefDirVecPos);
12554  }
12555  if(PrefDirVector.size() == 0)
12556  {
12557  Utilities->CallLogPop(154);
12558  return(true);
12559  }
12560  if(PrefDirVector.size() == 1)
12561  {
12562  PrefDirVector.at(x - 1).ELinkPos = -1;
12563  PrefDirVector.at(x - 1).ELink = -1;
12564  PrefDirVector.at(x - 1).XLinkPos = -1;
12565  PrefDirVector.at(x - 1).XLink = -1;
12566  PrefDirVector.at(x - 1).EXNumber = -1;
12567  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12568  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12569  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12570  Utilities->CallLogPop(155);
12571  return(true);
12572  }
12573  // here with truncate element not first element, so ELink & ELinkPos set
12574  // unset XLink & Pos if a leading point
12575  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12576  {
12577  PrefDirVector.at(x - 1).XLinkPos = -1;
12578  PrefDirVector.at(x - 1).XLink = -1;
12579  PrefDirVector.at(x - 1).EXNumber = -1;
12580  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12581  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12582  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12583  Utilities->CallLogPop(156);
12584  return(true);
12585  }
12586  Utilities->CallLogPop(157);
12587  return(true);
12588  }
12589  }
12590  Utilities->CallLogPop(158);
12591  return(false);
12592 }
12593 
12594 // ---------------------------------------------------------------------------
12595 
12596 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12597 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12598 /*
12599  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12600  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12601  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12602  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12603  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12604  displayed.
12605 */
12606 {
12607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12608  AnsiString((short)BuildingPrefDir));
12609  int HPos, VPos;
12610 
12611  if(PrefDirSize() == 0)
12612  {
12613  Utilities->CallLogPop(159);
12614  return;
12615  }
12616  for(unsigned int x = 0; x < PrefDirSize(); x++)
12617  {
12618  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12619 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12620 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12621 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12622  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12623  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12624  // only the front half of which will be overplotted by the back of the train, then when the train is
12625  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12626  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12627  {
12628  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12629  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12630  {
12631  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12632  }
12633  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12634  // Route, no direction if a single element
12635  {
12636  if(x == 0)
12637  {
12638  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12639  }
12640  if(x == (PrefDirSize() - 1))
12641  {
12642  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12643  }
12644  }
12645  }
12646  }
12647 
12648 // set start & end element colours if building a PrefDir
12649  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12650  {
12651  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12652  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12653  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12654  // set last element colour
12655  if(PrefDirSize() > 1)
12656  {
12657  unsigned int LatestPos = PrefDirSize() - 1;
12658  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12659  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12660  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12661  }
12662  }
12663  Disp->Update();
12664  Utilities->CallLogPop(160);
12665 }
12666 
12667 // ---------------------------------------------------------------------------
12668 
12670 /*
12671  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12672  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12673 */
12674 {
12675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12676  if(PrefDirSize() == 0)
12677  {
12678  Utilities->CallLogPop(1547);
12679  return;
12680  }
12681  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12682  bool FoundFlag;
12684  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12685 
12686  while(MMIT != PrefDir4MultiMap.end())
12687  {
12688  H = MMIT->first.first;
12689  V = MMIT->first.second;
12690  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12691  // always found in order, any missing have PrefDirPosx == -1
12692  if(PrefDirPos0 > -1)
12693  {
12694  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12695  }
12696  if(PrefDirPos1 > -1)
12697  {
12698  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12699  }
12700  if(PrefDirPos2 > -1)
12701  {
12702  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12703  }
12704  if(PrefDirPos3 > -1)
12705  {
12706  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12707  }
12708  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12709  {
12710  // need to plot all 4 in order to obtain all the direction graphics
12711  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12712  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12713  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12714  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12715  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12716  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12717  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12718  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12719  MMIT++;
12720  MMIT++;
12721  MMIT++;
12722  MMIT++;
12723  }
12724  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12725  {
12726  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12727  {
12728  // 0 & 1 constitute the bidirectional PrefDir
12729  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12730  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12731  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12732  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12733  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12734  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12735  MMIT++;
12736  MMIT++;
12737  MMIT++;
12738  }
12739  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12740  {
12741  // 0 & 2 constitute the bidirectional PrefDir
12742  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12743  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12744  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12745  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12746  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12747  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12748  MMIT++;
12749  MMIT++;
12750  MMIT++;
12751  }
12752  else
12753  {
12754  // 1 & 2 constitute the bidirectional PrefDir
12755  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12756  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12757  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12758  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12759  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12760  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12761  MMIT++;
12762  MMIT++;
12763  MMIT++;
12764  }
12765  }
12766  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12767  {
12768  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12769  {
12770  // 0 & 1 constitute the bidirectional PrefDir
12771  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12772  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12773  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12774  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12775  MMIT++;
12776  MMIT++;
12777  }
12778  else
12779  {
12780  // 2 unidirectional PrefDirs
12781  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12782  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12783  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12784  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12785  MMIT++;
12786  MMIT++;
12787  }
12788  }
12789  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12790  {
12791  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12792  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12793  MMIT++;
12794  }
12795  }
12796  Disp->Update();
12797  Utilities->CallLogPop(1548);
12798 }
12799 
12800 // ---------------------------------------------------------------------------
12801 
12802 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12803 {
12804  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12805  int TempInt;
12806 
12807  ClearPrefDir();
12808  int NumberOfPrefDirElements = 0;
12809 
12810  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12811  for(int x = 0; x < NumberOfPrefDirElements; x++)
12812  {
12813  VecFile >> TempInt; // TrackVectorPosition
12814  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12815  LoadPrefDirElement.TrackVectorPosition = TempInt;
12816  VecFile >> TempInt;
12817  LoadPrefDirElement.ELink = TempInt;
12818  VecFile >> TempInt;
12819  LoadPrefDirElement.ELinkPos = TempInt;
12820  VecFile >> TempInt;
12821  LoadPrefDirElement.XLink = TempInt;
12822  VecFile >> TempInt;
12823  LoadPrefDirElement.XLinkPos = TempInt;
12824  VecFile >> TempInt;
12825  LoadPrefDirElement.EXNumber = TempInt;
12826  VecFile >> TempInt;
12827  LoadPrefDirElement.CheckCount = TempInt;
12828  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12829  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12830  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12831  if(!(LoadPrefDirElement.IsARoute))
12832  {
12833  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12834  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12835  }
12836  else
12837  {
12838  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12839  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12840  LoadPrefDirElement.PrefDirRoute);
12841  }
12842  StorePrefDirElement(5, LoadPrefDirElement);
12843  Utilities->LoadFileString(VecFile); // marker
12844  }
12846  Utilities->CallLogPop(161);
12847 }
12848 
12849 // ---------------------------------------------------------------------------
12850 
12851 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12852 {
12853  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12854  int TempInt;
12855 
12856  ClearPrefDir();
12857  int NumberOfPrefDirElements = 0;
12858 
12859  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12860  for(int x = 0; x < NumberOfPrefDirElements; x++)
12861  {
12862  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12863  VecFile >> TempInt; // TrackVectorPosition
12864  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12865  LoadPrefDirElement.TrackVectorPosition = TempInt;
12866  VecFile >> TempInt;
12867  LoadPrefDirElement.ELink = TempInt;
12868  VecFile >> TempInt;
12869  LoadPrefDirElement.ELinkPos = TempInt;
12870  VecFile >> TempInt;
12871  LoadPrefDirElement.XLink = TempInt;
12872  VecFile >> TempInt;
12873  LoadPrefDirElement.XLinkPos = TempInt;
12874  VecFile >> TempInt;
12875  LoadPrefDirElement.EXNumber = TempInt;
12876  VecFile >> TempInt;
12877  LoadPrefDirElement.CheckCount = TempInt;
12878  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12879  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12880  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12881  if(!(LoadPrefDirElement.IsARoute))
12882  {
12883  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12884  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12885  }
12886  else
12887  {
12888  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12889  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12890  LoadPrefDirElement.PrefDirRoute);
12891  }
12892  StorePrefDirElement(0, LoadPrefDirElement);
12893  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12894  }
12896  Utilities->CallLogPop(1509);
12897 }
12898 
12899 // ---------------------------------------------------------------------------
12900 
12901 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12902 /*
12903  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12904  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12905 */
12906 {
12907  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12908  int TempInt;
12909  int NumberOfPrefDirElements = 0;
12910 
12911  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12912  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12913  {
12914  Utilities->CallLogPop(1152);
12915  return(false);
12916  }
12917  for(int x = 0; x < NumberOfPrefDirElements; x++)
12918  {
12919  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12920  {
12921  Utilities->CallLogPop(1766);
12922  return(false);
12923  }
12924  VecFile >> TempInt;
12925  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12926  {
12927  Utilities->CallLogPop(163);
12928  return(false);
12929  }
12930  VecFile >> TempInt;
12931  if((TempInt < -1) || (TempInt > 9)) // ELink
12932  {
12933  Utilities->CallLogPop(162);
12934  return(false);
12935  }
12936  VecFile >> TempInt;
12937  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12938  {
12939  Utilities->CallLogPop(164);
12940  return(false);
12941  }
12942  VecFile >> TempInt;
12943  if((TempInt < -1) || (TempInt > 9)) // XLink
12944  {
12945  Utilities->CallLogPop(165);
12946  return(false);
12947  }
12948  VecFile >> TempInt;
12949  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12950  {
12951  Utilities->CallLogPop(166);
12952  return(false);
12953  }
12954  VecFile >> TempInt;
12955  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12956  {
12957  Utilities->CallLogPop(167);
12958  return(false);
12959  }
12960  VecFile >> TempInt;
12961  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12962  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12963  // ELinkPos, XLink, XLinkPos & EXNumber
12964  {
12965  Utilities->CallLogPop(168);
12966  return(false);
12967  }
12968  VecFile >> TempInt;
12969  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12970  {
12971  Utilities->CallLogPop(1147);
12972  return(false);
12973  }
12974  VecFile >> TempInt;
12975  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12976  {
12977  Utilities->CallLogPop(1510);
12978  return(false);
12979  }
12980  VecFile >> TempInt;
12981  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12982  {
12983  Utilities->CallLogPop(1148);
12984  return(false);
12985  }
12986  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12987  {
12988  Utilities->CallLogPop(1700);
12989  return(false);
12990  }
12991  }
12992  Utilities->CallLogPop(169);
12993  return(true);
12994 }
12995 
12996 // ---------------------------------------------------------------------------
12997 
12998 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12999 {
13000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13001  int NumberOfPrefDirElements = PrefDirVector.size();
13002 
13003  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13004  for(int y = 0; y < NumberOfPrefDirElements; y++)
13005  {
13006  VecFile << y << '\n'; // extra
13007  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13008  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13009  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13010  VecFile << PrefDirVector.at(y).XLink << '\n';
13011  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13012  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13013  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13014  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13015  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13016  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13017  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13018  {
13019  VecFile << "************" << '\0' << '\n'; // marker
13020  }
13021  else
13022  {
13023  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13024  }
13025  }
13026  Utilities->CallLogPop(170);
13027 }
13028 
13029 // ---------------------------------------------------------------------------
13030 
13031 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13032 {
13033  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13034  int NumberOfSearchElements = SearchVector.size();
13035 
13036  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13037  for(int y = 0; y < NumberOfSearchElements; y++)
13038  {
13039  VecFile << y << '\n'; // extra
13040  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13041  VecFile << SearchVector.at(y).ELink << '\n';
13042  VecFile << SearchVector.at(y).ELinkPos << '\n';
13043  VecFile << SearchVector.at(y).XLink << '\n';
13044  VecFile << SearchVector.at(y).XLinkPos << '\n';
13045  VecFile << SearchVector.at(y).EXNumber << '\n';
13046  VecFile << SearchVector.at(y).CheckCount << '\n';
13047  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13048  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13049  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13050  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13051  {
13052  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13053  }
13054  else
13055  {
13056  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13057  }
13058  }
13059  Utilities->CallLogPop(1847);
13060 }
13061 
13062 // ---------------------------------------------------------------------------
13063 
13064 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13065 /*
13066  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13067  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13068 */
13069 {
13070  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13071  AnsiString(VLoc));
13072  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13073 
13074  if(VecPos > -1)
13075  {
13076  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13077  }
13078  else
13079  {
13080  Utilities->CallLogPop(171);
13081  return;
13082  }
13083  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13084  if(VecPos > -1)
13085  {
13086  ErasePrefDirElementAt(3, VecPos);
13087  }
13088  else
13089  {
13090  Utilities->CallLogPop(172);
13091  return;
13092  }
13093  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13094  if(VecPos > -1)
13095  {
13096  ErasePrefDirElementAt(4, VecPos);
13097  }
13098  else
13099  {
13100  Utilities->CallLogPop(173);
13101  return;
13102  }
13103  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13104  if(VecPos > -1)
13105  {
13106  ErasePrefDirElementAt(5, VecPos);
13107  }
13108  else
13109  {
13110  Utilities->CallLogPop(174);
13111  return;
13112  }
13113  Utilities->CallLogPop(175);
13114 }
13115 
13116 // ---------------------------------------------------------------------------
13117 /*
13118  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13119  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13120 
13121  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13122  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13123  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13124  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13125  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13126  PrefDirVector to correspond to the new track layout.
13127 
13128  {
13129  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13130  if(PrefDirSize() == 0)
13131  {
13132  Utilities->CallLogPop(176);
13133  return;
13134  }
13135  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13136  {
13137  int TV = PrefDirVector.at(x).TrackVectorPosition;
13138  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13139  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13140  if(Track->BlankElementAt(0, TV))
13141  {
13142  ErasePrefDirElementAt(6, x);
13143  }
13144  //if was a blankelement at x then ConnELink and ConnXLink both -1
13145  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13146  {
13147  ErasePrefDirElementAt(7, x);
13148  }
13149  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13150  //needs to be erased once, but if don't use 'else' then will erase two elements
13151  //since 'x' will correspond to the element after the first erased element
13152  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13153  {
13154  ErasePrefDirElementAt(8, x);
13155  }
13156  }
13157  Utilities->CallLogPop(177);
13158  }
13159 */
13160 // ---------------------------------------------------------------------------
13161 
13162 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13163 /*
13164  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13165  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13166 */
13167 {
13168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13169  bool AlreadyPresent, FoundFlag;
13170  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13171 
13172  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13173  {
13174  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13175  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13176  AlreadyPresent = false;
13177  if(FoundFlag)
13178  {
13179  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13180  {
13181  AlreadyPresent = true;
13182  }
13183  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13184  {
13185  AlreadyPresent = true;
13186  }
13187  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13188  {
13189  AlreadyPresent = true;
13190  }
13191  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13192  {
13193  AlreadyPresent = true;
13194  }
13195  }
13196  if(!AlreadyPresent)
13197  {
13198  StorePrefDirElement(4, TempElement);
13199  }
13200  }
13202  Utilities->CallLogPop(178);
13203 }
13204 /* earlier brute force search
13205  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13206  {
13207  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13208  bool AlreadyPresent = false;
13209  for(unsigned int y = 0;y<PrefDirSize();y++)
13210  {
13211  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13212  }
13213  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13214  }
13215 */
13216 
13217 // ---------------------------------------------------------------------------
13218 
13220 /*
13221  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13222  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13223  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13224  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13225  positions are likely to have changed, so this function is called to reset all the necessary connections and
13226  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13227  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13228  shouldn't have changed.
13229 */
13230 {
13231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13232  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13233  {
13234  bool FoundFlag;
13235  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13236  if(FoundFlag)
13237  {
13238  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13239  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13240  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13241  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13242  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13243  for(unsigned int z = 0; z < 4; z++)
13244  {
13245  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13246  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13247  }
13248  }
13249  else
13250  {
13251  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13252  }
13253  }
13254  Utilities->CallLogPop(179);
13255 }
13256 
13257 // ---------------------------------------------------------------------------
13258 
13260 /*
13261  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13262 */
13263 {
13264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13265  bool DiscrepancyFound = false;
13266 
13267  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13268  {
13269  bool FoundFlag;
13270  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13271  if(FoundFlag)
13272  {
13273  TPrefDirElement PE = PrefDirVector.at(x);
13274  if(PE.TrackVectorPosition != VecPos)
13275  {
13276  DiscrepancyFound = true;
13277  break;
13278  }
13279  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13280  {
13281  DiscrepancyFound = true;
13282  break;
13283  }
13284  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13285  {
13286  DiscrepancyFound = true;
13287  break;
13288  }
13289  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13290  {
13291  DiscrepancyFound = true;
13292  break;
13293  }
13294  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13295  {
13296  DiscrepancyFound = true;
13297  break;
13298  }
13299  }
13300  else
13301  {
13302  DiscrepancyFound = true;
13303  }
13304  }
13305  if(DiscrepancyFound)
13306  {
13307  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13308  ClearPrefDir(); // also clears multimap
13309  }
13310  Utilities->CallLogPop(1436);
13311 }
13312 
13313 // ---------------------------------------------------------------------------
13314 
13316 /*
13317  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13318  return true for OK
13319 */
13320 {
13321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13322  bool DiscrepancyFound = false;
13323 
13324  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13325  {
13326  bool FoundFlag;
13327  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13328  if(FoundFlag)
13329  {
13330  TPrefDirElement PE = PrefDirVector.at(x);
13331  if(PE.TrackVectorPosition != VecPos)
13332  {
13333  DiscrepancyFound = true;
13334  }
13335  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13336  {
13337  DiscrepancyFound = true;
13338  break;
13339  }
13340  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13341  {
13342  DiscrepancyFound = true;
13343  break;
13344  }
13345  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13346  {
13347  DiscrepancyFound = true;
13348  break;
13349  }
13350  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13351  {
13352  DiscrepancyFound = true;
13353  break;
13354  }
13355  }
13356  else
13357  {
13358  DiscrepancyFound = true;
13359  }
13360  }
13361  Utilities->CallLogPop(1512);
13362  return(!DiscrepancyFound);
13363 }
13364 
13365 // ---------------------------------------------------------------------------
13366 
13367 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13368 /*
13369  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13370  turn and for the overall sizes.
13371 */
13372 {
13373  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13374  bool FoundFlag = false;
13375  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13376 
13377  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13378  {
13379  TPrefDirElement CheckElement = PrefDirVector.at(a);
13380  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13381  if(!FoundFlag)
13382  {
13383  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13384  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13385  }
13386  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13387  {
13388  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13389  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13390  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13391  }
13392  }
13393  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13394  {
13395  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13396  + " Caller=" + (AnsiString)Caller);
13397  }
13398  Utilities->CallLogPop(180);
13399 }
13400 
13401 // ---------------------------------------------------------------------------
13402 
13403 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13404  int &PrefDirPos3)
13405 /*
13406  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13407  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13408  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13409  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13410  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13411 */
13412 {
13413  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13414  AnsiString(VLoc));
13415  THVPair PrefDirMapKeyPair;
13416 
13417  PrefDirPos0 = -1;
13418  PrefDirPos1 = -1;
13419  PrefDirPos2 = -1;
13420  PrefDirPos3 = -1;
13421  FoundFlag = false;
13422  PrefDirMapKeyPair.first = HLoc;
13423  PrefDirMapKeyPair.second = VLoc;
13424  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13425 
13426  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13427  if(ItPair.first == ItPair.second) //none found
13428  {
13429  Utilities->CallLogPop(181);
13430  return;
13431  }
13432  else
13433  {
13434  FoundFlag = true;
13435  PrefDirPos0 = ItPair.first->second;
13436  ItPair.first++;
13437  if(ItPair.first == ItPair.second)
13438  {
13439  Utilities->CallLogPop(182); //only one found
13440  return;
13441  }
13442  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13443  {
13444  PrefDirPos1 = ItPair.first->second;
13445  }
13446  ItPair.first++;
13447  if(ItPair.first == ItPair.second)
13448  {
13449  Utilities->CallLogPop(183); //2 found
13450  return;
13451  }
13452  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13453  {
13454  PrefDirPos2 = ItPair.first->second;
13455  }
13456  ItPair.first++;
13457  if(ItPair.first == ItPair.second)
13458  {
13459  Utilities->CallLogPop(184); //3 found
13460  return;
13461  }
13462  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13463  {
13464  PrefDirPos3 = ItPair.first->second; //4 found
13465  }
13466  }
13467  Utilities->CallLogPop(185);
13468 }
13469 
13470 // ---------------------------------------------------------------------------
13471 
13472 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13473 { //not used after modified the pref dir checking function at v2.13.0
13474  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13475  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13476  try
13477  {
13478  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13479  + "," + AnsiString(LinkNumberPos));
13480  bool FoundFlag;
13481  int PD0, PD1, PD2, PD3;
13482  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13483  {
13484  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13485  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13486  PD0, PD1, PD2, PD3);
13487  if(!FoundFlag)
13488  {
13489  Utilities->CallLogPop(2282);
13490  return(false);
13491  }
13492  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13493  {
13494  if(PD0 > -1)
13495  {
13496  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13497  {
13498  LinkedPrefDirVectorNumber = PD0;
13499  Utilities->CallLogPop(2283);
13500  return(true);
13501  }
13502  }
13503  if(PD1 > -1)
13504  {
13505  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13506  {
13507  LinkedPrefDirVectorNumber = PD1;
13508  Utilities->CallLogPop(2284);
13509  return(true);
13510  }
13511  }
13512  }
13513  if(PD0 > -1)
13514  {
13515  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13516  {
13517  LinkedPrefDirVectorNumber = PD0;
13518  Utilities->CallLogPop(2285);
13519  return(true);
13520  }
13521  }
13522  if(PD1 > -1)
13523  {
13524  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13525  {
13526  LinkedPrefDirVectorNumber = PD1;
13527  Utilities->CallLogPop(2286);
13528  return(true);
13529  }
13530  }
13531  if(PD2 > -1)
13532  {
13533  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13534  {
13535  LinkedPrefDirVectorNumber = PD2;
13536  Utilities->CallLogPop(2287);
13537  return(true);
13538  }
13539  }
13540  if(PD3 > -1)
13541  {
13542  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13543  {
13544  LinkedPrefDirVectorNumber = PD3;
13545  Utilities->CallLogPop(2288);
13546  return(true);
13547  }
13548  }
13549  LinkedPrefDirVectorNumber = -1;
13550  Utilities->CallLogPop(2289);
13551  return(false);
13552  }
13553  else //buffer or continuation, no link at position 0 but not a failure
13554  {
13555  LinkedPrefDirVectorNumber = -1;
13556  Utilities->CallLogPop(2290);
13557  return(true);
13558  }
13559  }
13560  catch(const Exception &e) //non error catch
13561  {
13562  LinkedPrefDirVectorNumber = -1;
13563  Utilities->CallLogPop(2291);
13564  return(false);
13565  }
13566 }
13567 
13568 // ---------------------------------------------------------------------------
13569 
13570 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13571 { //not used after modified the pref dir checking function at v2.13.0
13572  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
13573  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13574  try
13575  {
13576  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
13577  + "," + AnsiString(LinkNumberPos));
13578  bool FoundFlag;
13579  int PD0, PD1, PD2, PD3;
13580  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13581  {
13582  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13583  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13584  PD0, PD1, PD2, PD3);
13585  if(!FoundFlag)
13586  {
13587  Utilities->CallLogPop(2468);
13588  return(false);
13589  }
13590  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13591  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
13592  if(PD0 > -1)
13593  {
13594  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
13595  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
13596  {
13597  LinkedPrefDirVectorNumber = PD0;
13598  Utilities->CallLogPop(2469);
13599  return(true);
13600  }
13601  }
13602  if(PD1 > -1)
13603  {
13604  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
13605  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
13606  {
13607  LinkedPrefDirVectorNumber = PD1;
13608  Utilities->CallLogPop(2470);
13609  return(true);
13610  }
13611  }
13612  LinkedPrefDirVectorNumber = -1;
13613  Utilities->CallLogPop(2471);
13614  return(false);
13615  }
13616  if(PD0 > -1)
13617  {
13618  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13619  {
13620  LinkedPrefDirVectorNumber = PD0;
13621  Utilities->CallLogPop(2472);
13622  return(true);
13623  }
13624  }
13625  if(PD1 > -1)
13626  {
13627  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13628  {
13629  LinkedPrefDirVectorNumber = PD1;
13630  Utilities->CallLogPop(2473);
13631  return(true);
13632  }
13633  }
13634  if(PD2 > -1)
13635  {
13636  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13637  {
13638  LinkedPrefDirVectorNumber = PD2;
13639  Utilities->CallLogPop(2474);
13640  return(true);
13641  }
13642  }
13643  if(PD3 > -1)
13644  {
13645  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13646  {
13647  LinkedPrefDirVectorNumber = PD3;
13648  Utilities->CallLogPop(2475);
13649  return(true);
13650  }
13651  }
13652  LinkedPrefDirVectorNumber = -1;
13653  Utilities->CallLogPop(2476);
13654  return(false);
13655  }
13656  else //buffer or continuation, no link at position 0 but not a failure
13657  {
13658  LinkedPrefDirVectorNumber = -1;
13659  Utilities->CallLogPop(2477);
13660  return(true);
13661  }
13662  }
13663  catch(const Exception &e) //non error catch
13664  {
13665  LinkedPrefDirVectorNumber = -1;
13666  Utilities->CallLogPop(2478);
13667  return(false);
13668  }
13669 }
13670 
13671 // ---------------------------------------------------------------------------
13672 
13674 {
13675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13676  bool FoundFlag; //not used
13677  int PD0, PD1, PD2, PD3;
13678  //recover all PDs at the H & V of PDPtr
13679  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13680 
13681  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13682  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13683 
13684  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13685  {
13686  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13687  {
13688  Utilities->CallLogPop(2292);
13689  return(true);
13690  }
13691  }
13692  if(PD1 > -1)
13693  {
13694  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13695  {
13696  Utilities->CallLogPop(2293);
13697  return(true);
13698  }
13699  }
13700  if(PD2 > -1)
13701  {
13702  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13703  {
13704  Utilities->CallLogPop(2294);
13705  return(true);
13706  }
13707  }
13708  if(PD3 > -1)
13709  {
13710  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13711  {
13712  Utilities->CallLogPop(2295);
13713  return(true);
13714  }
13715  }
13716  Utilities->CallLogPop(2296);
13717  return(false);
13718 }
13719 
13720 // ---------------------------------------------------------------------------
13721 
13722 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13723 /*
13724  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13725 */
13726 {
13727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13728  PrefDirVector.push_back(LoadPrefDirElement);
13729  THVPair PrefDir4MultiMapKeyPair;
13730  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13731 
13732  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13733  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13734  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13735  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13736  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13737 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13738  Utilities->CallLogPop(186);
13739 }
13740 
13741 // ---------------------------------------------------------------------------
13742 
13743 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13744 /*
13745  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13746  4MultiMap if they are greater than the erased value.
13747 */
13748 {
13749  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13750  bool FoundFlag;
13751 
13752  if(!PrefDirVector.empty())
13753  {
13754  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13755  if(!FoundFlag)
13756  {
13757  throw Exception("Failed to find PrefDir4MultiMap erase element");
13758  }
13759  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13760  PrefDir4MultiMap.erase(EraseIt);
13761  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13763  }
13764  Utilities->CallLogPop(187);
13765 }
13766 
13767 // ---------------------------------------------------------------------------
13768 
13769 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13770 /*
13771  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13772  4MultiMap if they are greater than the erased value.
13773 */
13774 {
13775  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13776  AnsiString(ErasedElementNumber));
13777  if(!PrefDir4MultiMap.empty())
13778  {
13779  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13780  {
13781  if(MapPtr->second > ErasedElementNumber)
13782  {
13783  MapPtr->second--;
13784  }
13785  }
13786  }
13787  Utilities->CallLogPop(1450);
13788 }
13789 
13790 // ---------------------------------------------------------------------------
13791 
13792 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13793 /*
13794  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13795  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13796  nothing is found this is an error but the error message is given in the calling function.
13797 */
13798 {
13799  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13800  FoundFlag = false;
13801  if(PrefDirVectorPosition >= PrefDirVector.size())
13802  {
13803  throw Exception("PrefDirVectorPosition out of range");
13804  }
13805  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13806  THVPair PrefDir4MultiMapKeyPair;
13807 
13808  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13809  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13810  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13811 
13812  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13813  if(ItPair.first == ItPair.second)
13814  {
13815  Utilities->CallLogPop(188);
13816  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13817  }
13818  else
13819  {
13820  if(ItPair.first->second == PrefDirVectorPosition)
13821  {
13822  FoundFlag = true;
13823  Utilities->CallLogPop(189);
13824  return(ItPair.first);
13825  }
13826  ItPair.first++;
13827  if(ItPair.first == ItPair.second)
13828  {
13829  Utilities->CallLogPop(190);
13830  return(ItPair.first); // nothing found
13831  }
13832  if(ItPair.first->second == PrefDirVectorPosition)
13833  {
13834  FoundFlag = true;
13835  Utilities->CallLogPop(191);
13836  return(ItPair.first);
13837  }
13838  ItPair.first++;
13839  if(ItPair.first == ItPair.second)
13840  {
13841  Utilities->CallLogPop(192);
13842  return(ItPair.first); // nothing found
13843  }
13844  if(ItPair.first->second == PrefDirVectorPosition)
13845  {
13846  FoundFlag = true;
13847  Utilities->CallLogPop(193);
13848  return(ItPair.first);
13849  }
13850  ItPair.first++;
13851  if(ItPair.first == ItPair.second)
13852  {
13853  Utilities->CallLogPop(194);
13854  return(ItPair.first); // nothing found
13855  }
13856  if(ItPair.first->second == PrefDirVectorPosition)
13857  {
13858  FoundFlag = true;
13859  Utilities->CallLogPop(195);
13860  return(ItPair.first);
13861  }
13862  }
13863  Utilities->CallLogPop(196);
13864  return(ItPair.first); // nothing found
13865 }
13866 
13867 // ---------------------------------------------------------------------------
13868 
13869 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13870 /*
13871  Although there may be up to four entries at one H & V position this function gets just one. It is
13872  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13873  at H & V.
13874 */
13875 {
13876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13877  THVPair PrefDir4MultiMapKeyPair;
13878 
13879  PrefDir4MultiMapKeyPair.first = HLoc;
13880  PrefDir4MultiMapKeyPair.second = VLoc;
13881  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13882 
13883  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13884  if(ItPair.first == ItPair.second) // nothing found
13885  {
13886  Utilities->CallLogPop(197);
13887  return(-1);
13888  }
13889  else
13890  {
13891  Utilities->CallLogPop(198);
13892  return(ItPair.first->second);
13893  }
13894 }
13895 
13896 // ---------------------------------------------------------------------------
13897 
13898 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13899 {
13900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13901  bool ErasedFlag = false;
13902 
13903  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13904  {
13905  if(PrefDirSize() == 0)
13906  {
13907  Utilities->CallLogPop(1511);
13908  return;
13909  }
13910  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13911  {
13912  ErasedFlag = false;
13913  // use 'else' to ensure don't try to access an erased element
13914  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13915  {
13916  ErasePrefDirElementAt(11, x);
13917  ErasedFlag = true;
13918  }
13919  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13920  {
13921  ErasePrefDirElementAt(12, x);
13922  ErasedFlag = true;
13923  }
13924  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13925  {
13926  ErasePrefDirElementAt(13, x);
13927  ErasedFlag = true;
13928  }
13929  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13930  {
13931  ErasePrefDirElementAt(9, x);
13932  ErasedFlag = true;
13933  }
13934  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13935  {
13936  ErasePrefDirElementAt(10, x);
13937  ErasedFlag = true;
13938  }
13939  if(!ErasedFlag)
13940  {
13941  // don't use 'else' here as may be more than one that need decrementing
13942  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13943  {
13944  PrefDirVector.at(x).TrackVectorPosition--;
13945  }
13946  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13947  {
13948  PrefDirVector.at(x).Conn[0]--;
13949  }
13950  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13951  {
13952  PrefDirVector.at(x).Conn[1]--;
13953  }
13954  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13955  {
13956  PrefDirVector.at(x).Conn[2]--;
13957  }
13958  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13959  {
13960  PrefDirVector.at(x).Conn[3]--;
13961  }
13962  }
13963  }
13964  }
13965  Utilities->CallLogPop(1434);
13966 }
13967 
13968 // ---------------------------------------------------------------------------
13969 
13970 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13971 {
13972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13973  OverallDistance = 0;
13974  OverallSpeedLimit = 0;
13975  LeadingPointsAtLastElement = false;
13976  if(PrefDirSize() == 0) // shouldn't be empty when this called
13977  {
13978  Utilities->CallLogPop(1491);
13979  return;
13980  }
13981  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13982  {
13983  LeadingPointsAtLastElement = true;
13984  Utilities->CallLogPop(1492);
13985  return;
13986  }
13987  for(unsigned int x = 0; x < PrefDirSize(); x++)
13988  {
13989  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13990  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13991  {
13992  OverallDistance += PrefDirElement.Length23;
13993  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13994  {
13995  if(x == 0)
13996  {
13997  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13998  }
13999  else
14000  {
14001  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14002  {
14003  OverallSpeedLimit = -1;
14004  }
14005  }
14006  }
14007  }
14008  else
14009  {
14010  OverallDistance += PrefDirElement.Length01;
14011  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14012  {
14013  if(x == 0)
14014  {
14015  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14016  }
14017  else
14018  {
14019  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14020  {
14021  OverallSpeedLimit = -1;
14022  }
14023  }
14024  }
14025  }
14026  }
14027  Utilities->CallLogPop(1529);
14028 }
14029 
14030 // ---------------------------------------------------------------------------
14031 
14032 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14033 {
14034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14035  if(PrefDirSize() == 0)
14036  {
14037  Utilities->CallLogPop(1564);
14038  return;
14039  }
14040  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14041  bool FoundFlag;
14043  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14044 
14045  while(MMIT != PrefDir4MultiMap.end())
14046  {
14047  HLoc = MMIT->first.first;
14048  VLoc = MMIT->first.second;
14049  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14050  H = HLoc - Track->GetHLocMin();
14051  V = VLoc - Track->GetVLocMin();
14052  // always found in order, any missing have PrefDirPosx == -1
14053  if(PrefDirPos0 > -1)
14054  {
14055  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14056  }
14057  if(PrefDirPos1 > -1)
14058  {
14059  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14060  }
14061  if(PrefDirPos2 > -1)
14062  {
14063  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14064  }
14065  if(PrefDirPos3 > -1)
14066  {
14067  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14068  }
14069  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14070  {
14071  // need to plot all 4 in order to obtain all the direction graphics
14072  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14073  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14074  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14075  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14076  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14077  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14078  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14079  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14080  MMIT++;
14081  MMIT++;
14082  MMIT++;
14083  MMIT++;
14084  }
14085  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14086  {
14087  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14088  {
14089  // 0 & 1 constitute the bidirectional PrefDir
14090  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14091  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14092  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14093  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14094  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14095  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14096  MMIT++;
14097  MMIT++;
14098  MMIT++;
14099  }
14100  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14101  {
14102  // 0 & 2 constitute the bidirectional PrefDir
14103  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14104  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14105  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14106  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14107  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14108  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14109  MMIT++;
14110  MMIT++;
14111  MMIT++;
14112  }
14113  else
14114  {
14115  // 1 & 2 constitute the bidirectional PrefDir
14116  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14117  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14118  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14119  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14120  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14121  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14122  MMIT++;
14123  MMIT++;
14124  MMIT++;
14125  }
14126  }
14127  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14128  {
14129  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14130  {
14131  // 0 & 1 constitute the bidirectional PrefDir
14132  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14133  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14134  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14135  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14136  MMIT++;
14137  MMIT++;
14138  }
14139  else
14140  {
14141  // 2 unidirectional PrefDirs
14142  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14143  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14144  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14145  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14146  MMIT++;
14147  MMIT++;
14148  }
14149  }
14150  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14151  {
14152  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14153  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14154  MMIT++;
14155  }
14156  }
14157  Utilities->CallLogPop(1565);
14158 }
14159 
14160 // ---------------------------------------------------------------------------
14161 
14162 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14163 /*
14164  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14165  level crossing, signals with wrong direction set, or buffers.
14166 */
14167 {
14168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14169  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14170  bool FoundFlag;
14172  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14173 
14174  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14175  ElementIn.VLoc)))
14176  {
14177  Utilities->CallLogPop(1982);
14178  return(false);
14179  }
14180  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
14181  {
14182  Utilities->CallLogPop(1983);
14183  return(false);
14184  }
14185 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
14186  {
14187  Utilities->CallLogPop(1995);
14188  return(false);
14189  }
14190 */
14191 // Now check that there is only a single prefdir set
14192  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14193 // always found in order, any missing have PrefDirPosx == -1
14194  if(PrefDirPos0 > -1)
14195  {
14196  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14197  }
14198  if(PrefDirPos1 > -1)
14199  {
14200  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14201  }
14202  if(PrefDirPos2 > -1)
14203  {
14204  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14205  }
14206  if(PrefDirPos3 > -1)
14207  {
14208  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14209  }
14210  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14211  {
14212  Utilities->CallLogPop(1984);
14213  return(false);
14214  }
14215  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14216  {
14217  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14218  {
14219  Utilities->CallLogPop(1985);
14220  return(false);
14221  }
14222  else
14223  {
14224  Utilities->CallLogPop(1986);
14225  return(true);
14226  }
14227  }
14228  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14229  {
14230  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14231  {
14232  Utilities->CallLogPop(1987);
14233  return(false);
14234  }
14235  else
14236  {
14237  Utilities->CallLogPop(1988);
14238  return(true);
14239  }
14240  }
14241  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14242  {
14243  if(PrefDirElement0.XLinkPos == EntryPos)
14244  {
14245  Utilities->CallLogPop(1989);
14246  return(false);
14247  }
14248  else
14249  {
14250  Utilities->CallLogPop(1990);
14251  return(true);
14252  }
14253  }
14254  else
14255  {
14256  Utilities->CallLogPop(1991);
14257  return(false); // none found
14258  }
14259 }
14260 
14261 // ---------------------------------------------------------------------------
14262 
14264 {
14265 /* //Added at v2.1.0
14266  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14267  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14268  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14269  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14270  and can be modelled better anyway.
14271 
14272  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14273  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14274  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14275  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14276  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14277  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14278 */
14279  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14280  ElementIn.VLoc + "," + XLink);
14281  int TrackVecPos;
14282  bool TrackFoundFlag;
14283  TTrackElement TempTrackElement;
14284 
14285  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14286  {
14287  Utilities->CallLogPop(2047);
14288  return(false);
14289  }
14290 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14291  if(XLink == 1)
14292  {
14293  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14294  if(TrackFoundFlag)
14295  {
14296  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14297  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14298  {
14299  Utilities->CallLogPop(2048);
14300  return(true);
14301  }
14302  }
14303  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14304  if(TrackFoundFlag)
14305  {
14306  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14307  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14308  {
14309  Utilities->CallLogPop(2049);
14310  return(true);
14311  }
14312  }
14313  }
14314 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14315  if(XLink == 3)
14316  {
14317  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14318  if(TrackFoundFlag)
14319  {
14320  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14321  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14322  {
14323  Utilities->CallLogPop(2050);
14324  return(true);
14325  }
14326  }
14327  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14328  if(TrackFoundFlag)
14329  {
14330  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14331  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14332  {
14333  Utilities->CallLogPop(2051);
14334  return(true);
14335  }
14336  }
14337  }
14338 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14339  if(XLink == 7)
14340  {
14341  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14342  if(TrackFoundFlag)
14343  {
14344  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14345  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14346  {
14347  Utilities->CallLogPop(2052);
14348  return(true);
14349  }
14350  }
14351  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14352  if(TrackFoundFlag)
14353  {
14354  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14355  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14356  {
14357  Utilities->CallLogPop(2053);
14358  return(true);
14359  }
14360  }
14361  }
14362 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14363  if(XLink == 9)
14364  {
14365  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14366  if(TrackFoundFlag)
14367  {
14368  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14369  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14370  {
14371  Utilities->CallLogPop(2054);
14372  return(true);
14373  }
14374  }
14375  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14376  if(TrackFoundFlag)
14377  {
14378  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14379  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14380  {
14381  Utilities->CallLogPop(2055);
14382  return(true);
14383  }
14384  }
14385  }
14386  Utilities->CallLogPop(2056);
14387  return(false);
14388 }
14389 
14390 // ---------------------------------------------------------------------------
14391 
14392 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14393 {
14394 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14395  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14396  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14397  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14398  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14399 */
14400  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14402  bool FoundFlag, ContFlag, FoundElements = false;
14403  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14404  TPrefDirElement NextElement;
14405 
14406  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14407  {
14408  LastIteratorValue++;
14409  ContFlag = false;
14410  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14411  {
14412  continue;
14413  }
14414 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
14415  {
14416  continue;
14417  }
14418 */
14419 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14420  // found a potential route start point
14421  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14422  {
14423  continue;
14424  }
14425  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14426  {
14427  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14428  if(PDVIt->TrackType == Continuation)
14429  {
14430  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14431  {
14432  continue;
14433  }
14434  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14435  {
14436  continue;
14437  }
14438  }
14439  StartElement = *PDVIt;
14440 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14441  // diverging track on which there was no pref dir. See below for 2 required changes.
14442  }
14443  else
14444  {
14445  continue;
14446  }
14447  // now track along until find a signal or continuation, checking validity for each element
14448  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14449  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14450  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14451  if(PrefDirPos0 == -1) // no continuing prefdir
14452  {
14453  continue;
14454  }
14455  bool NextElementFoundFlag = false;
14456  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14457  {
14458  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14459  NextElementFoundFlag = true;
14460  }
14461  if(PrefDirPos1 > -1)
14462  {
14463  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14464  {
14465  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14466  NextElementFoundFlag = true;
14467  }
14468  }
14469  if(PrefDirPos2 > -1)
14470  {
14471  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14472  {
14473  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14474  NextElementFoundFlag = true;
14475  }
14476  }
14477  if(PrefDirPos3 > -1)
14478  {
14479  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14480  {
14481  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14482  NextElementFoundFlag = true;
14483  }
14484  }
14485  if(!NextElementFoundFlag)
14486  {
14487  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14488 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14489  }
14490  while(true)
14491  {
14492  // check validity
14493  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14494  {
14495  ContFlag = true;
14496  break;
14497  }
14498  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14499  {
14500  ContFlag = true;
14501  break;
14502  }
14503  // check if in a route, providing not a signal, as a signal might be at the start of a route
14504  if(NextElement.TrackType != SignalPost)
14505  {
14506  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14507  {
14508  ContFlag = true;
14509  break;
14510  }
14511  }
14512  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14513  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
14514  {
14515  EndElement = NextElement;
14516  break;
14517  }
14518  // get the next element in the sequence
14519  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14520  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14521  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14522  if(PrefDirPos0 == -1) // no continuing prefdir
14523  {
14524  ContFlag = true;
14525  break;
14526  }
14527  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14528  {
14529  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14530  continue;
14531  }
14532  if(PrefDirPos1 > -1)
14533  {
14534  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14535  {
14536  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14537  continue;
14538  }
14539  }
14540  if(PrefDirPos2 > -1)
14541  {
14542  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14543  {
14544  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14545  continue;
14546  }
14547  }
14548  if(PrefDirPos3 > -1)
14549  {
14550  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14551  {
14552  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14553  continue;
14554  }
14555  }
14556  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14557  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14558  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14559  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14560  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14561  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14562  {
14563  ContFlag = true;
14564  break;
14565  }
14566  else
14567  {
14568  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14569  // could drop the bridge test but keep it to show the change history
14570  break;
14571 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14572  }
14573  }
14574  if(ContFlag)
14575  {
14576  continue;
14577  }
14578  // else have start and end elements set & all elements valid, so set up the route segment
14579  FoundElements = true;
14580  break;
14581  }
14582  if(FoundElements)
14583  {
14584  Utilities->CallLogPop(1992);
14585  return(true);
14586  }
14587  else
14588  {
14589  Utilities->CallLogPop(1993);
14590  return(false);
14591  }
14592 }
14593 
14594 // ---------------------------------------------------------------------------
14595 // TOneRoute
14596 // ---------------------------------------------------------------------------
14597 
14598 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14599 {
14600 /* General:
14601  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14602  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14603  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14604  route will use automatic signals or not.
14605  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14606  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14607  elements, so additional work is needed to complete all their members before they are ready for conversion into
14608  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14609  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14610  ConvertAndAdd.......
14611 */
14612  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14613  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14614  ClearRoute();
14615  int TrackVectorPosition;
14616  TTrackElement TrackElement;
14617  TPrefDirElement FirstElement, LastElement;
14618 
14619  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14620  {
14621  Utilities->CallLogPop(199);
14622  return(false);
14623  }
14624  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14625  {
14626  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14627  Utilities->CallLogPop(1996);
14628  return(false);
14629  }
14630  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14631  {
14632  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14633  Utilities->CallLogPop(200);
14634  return(false);
14635  }
14636  if(Track->IsLCAtHV(18, HLoc, VLoc))
14637  {
14638  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14639  Utilities->CallLogPop(1909);
14640  return(false);
14641  }
14642 // check if selected a train & disallow if so
14643  if(TrackElement.TrainIDOnElement > -1)
14644  {
14645  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14646  Utilities->CallLogPop(202);
14647  return(false);
14648  }
14649 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14650  TPrefDirElement PrefDirElement;
14651  int LockedVectorNumber;
14652 
14653  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14654  {
14655  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14656  Utilities->CallLogPop(203);
14657  return(false);
14658  }
14659  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14660  {
14661  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14662  Utilities->CallLogPop(204);
14663  return(false);
14664  }
14666  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14667 // signal in an autosig route & follow with a non-autosig route
14668 
14669  TPrefDirElement BlankElement;
14670 
14671  StartElement1 = BlankElement;
14672  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14673 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14674  bool InPrefDirFlag = false;
14675 
14676  bool FoundFlag;
14677  int PrefDirPos0 = -1;
14678  int PrefDirPos1 = -1;
14679  int PrefDirPos2 = -1;
14680  int PrefDirPos3 = -1;
14681 
14683  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14684  int PrefDirVecPos[4] =
14685  {
14686  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14687  };
14688 
14689  for(int x = 0; x < 4; x++)
14690  {
14691  int b = PrefDirVecPos[x];
14692  if(b > -1)
14693  {
14694  // only allow the appropriate exit route to be searched
14695  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14696  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14697  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14698  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14699  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14700  {
14701  InPrefDirFlag = true;
14702  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14703  if(AutoSigsFlag)
14704  {
14705  StartElement1.AutoSignals = true;
14706  }
14707  StartElement1.PrefDirRoute = true;
14708  }
14709  }
14710  }
14711 
14712  if(!InPrefDirFlag)
14713  {
14714  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14715  Utilities->CallLogPop(205);
14716  return(false);
14717  }
14718 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14720  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14721 
14722  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14723  {
14724  throw Exception("Selection in two routes - should never happen!");
14725  }
14726  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14727  {
14728  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14729  {
14730  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14731  Utilities->CallLogPop(206);
14732  return(false);
14733  }
14734  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14735  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14736  {
14737  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14738  Utilities->CallLogPop(207);
14739  return(false);
14740  }
14741  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14742  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14743  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14744  {
14745  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14746  Utilities->CallLogPop(208);
14747  return(false);
14748  }
14749  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14751  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14752  if(AutoSigsFlag)
14753  {
14754  StartElement1.AutoSignals = true;
14755  }
14756  StartElement1.PrefDirRoute = true;
14758  Utilities->CallLogPop(209);
14759  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14760  }
14761 
14762  else // no route started
14763  {
14764 // check if selected position is adjacent to start or end of an existing route and disallow
14765  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14766  {
14767  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14768  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14769  {
14770  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14771  Utilities->CallLogPop(210);
14772  return(false);
14773  }
14774  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14775  {
14776  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14777  Utilities->CallLogPop(211);
14778  return(false);
14779  }
14780  }
14781 
14782 // check if it's adjacent to end of an existing route,
14783  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14784  {
14786  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14787  {
14788  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14789  Utilities->CallLogPop(212);
14790  return(false);
14791  }
14792  }
14793  SearchVector.push_back(StartElement1);
14794  Utilities->CallLogPop(213);
14795  return(true);
14796  }
14797 }
14798 
14799 // ---------------------------------------------------------------------------
14800 
14801 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14802  IDInt &ReqPosRouteID, bool &PointsChanged)
14803 
14804 /*
14805  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14806 
14807  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14808  this being set to -1 for not used.
14809  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14810  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14811  Check correct type of element - signal/buffers/continuation.
14812  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14813  EndElement2 corresponding to the 2 possible PrefDir elements).
14814  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14815  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14816  linked forward to another route.
14817  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14818  for same position as start should cover this)
14819 
14820  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14821  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14822  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14823  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14824  If the search fails then return false.
14825  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14826  in the SearchVector to ensure it's entered as part of the new route.
14827  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14828  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14829  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14830  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14831  so return false, with an appropriate message if ConsecSignalsRoute set.
14832 */
14833 
14834 {
14835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14836  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14837  int EndPosition; // the position selected
14838  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
14839 
14840  Track->LCFoundInAutoSigsRoute = false;
14842  TotalSearchCount = 0;
14843  ReqPosRouteID = IDInt(-1); // default value for not used
14844  TTrackElement TrackElement;
14845  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14846  // given element as can't select 2-track elements
14847  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14848  {
14849  Utilities->CallLogPop(214);
14850  return(false);
14851  }
14852  if(Track->IsLCAtHV(19, HLoc, VLoc))
14853  {
14854  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14855  Utilities->CallLogPop(1908);
14856  return(false);
14857  }
14858 // cancel selection if on original start element
14859  if(EndPosition == StartRoutePosition)
14860  {
14861  Utilities->CallLogPop(215);
14862  return(false);
14863  }
14864  if(AutoSigsFlag)
14865  {
14866  if(TrackElement.TrackType == Buffers)
14867  {
14868  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14869  Utilities->CallLogPop(216);
14870  return(false);
14871  }
14872  }
14873  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14874  {
14875  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14876  Utilities->CallLogPop(217);
14877  return(false);
14878  }
14879 // check if train on element
14880  if(TrackElement.TrainIDOnElement > -1)
14881  {
14882  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14883  Utilities->CallLogPop(219);
14884  return(false);
14885  }
14886 // disallow if not in EveryPrefDir & set EndElement(s)
14887  bool InPrefDirFlag = false;
14888 
14889  bool FoundFlag;
14890  int PrefDirPos0 = -1;
14891  int PrefDirPos1 = -1;
14892  int PrefDirPos2 = -1;
14893  int PrefDirPos3 = -1;
14894 
14895  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14896  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14897  int PrefDirVecPos[4] =
14898  {
14899  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14900  };
14901 
14902  for(int x = 0; x < 4; x++)
14903  {
14904  int b = PrefDirVecPos[x];
14905  if(b > -1)
14906  {
14907  InPrefDirFlag = true;
14908  if(EndElement1.TrackVectorPosition == -1)
14909  {
14910  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14911  }
14912  else
14913  {
14914  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14915  }
14916  }
14917  }
14918  if(!InPrefDirFlag)
14919  {
14920  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14921  Utilities->CallLogPop(220);
14922  return(false);
14923  }
14924 // check if in an existing route - can't be a bridge so can use a simple 'find'
14925 // bool InRoute = false;
14927  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14928 
14929  if(RoutePair.first > -1)
14930  {
14931  if(RoutePair.second != 0) // not first element in existing route so no good
14932  {
14933  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14934  Utilities->CallLogPop(221);
14935  return(false);
14936  }
14937  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14938 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14939  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14940  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14941  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14942  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14943  {
14944  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14945  Utilities->CallLogPop(222);
14946  return(false);
14947  }
14948  EndElement1 = RouteElement;
14949  EndElement2 = BlankElement; // only need the route element
14950  EndPosition = EndElement1.TrackVectorPosition;
14951  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14952  }
14953 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14954 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14955 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14956 
14957  if(EndElement1.HLoc >= StartElement1.HLoc)
14958  {
14960  SearchLimitHighH = EndElement1.HLoc + 15;
14961  }
14962  else
14963  {
14964  SearchLimitLowH = EndElement1.HLoc - 15;
14966  }
14967  if(EndElement1.VLoc >= StartElement1.VLoc)
14968  {
14970  SearchLimitHighV = EndElement1.VLoc + 15;
14971  }
14972  else
14973  {
14974  SearchLimitLowV = EndElement1.VLoc - 15;
14976  }
14977 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14978  check & TotalSearchCounts check
14979  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14980  {
14981  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14982  Utilities->CallLogPop(1693);
14983  return false;
14984  }
14985 */
14986 // check if adjacent to start and disallow
14987  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14988  {
14990  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14991 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14992 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14993  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14994  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14995  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14996  {
14997  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14998  Utilities->CallLogPop(223);
14999  return(false);
15000  }
15001 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15002 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15003  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15004  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15005  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15006  {
15007  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15008  Utilities->CallLogPop(224);
15009  return(false);
15010  }
15011 // check if adjacent to end of a route & disallow
15013  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15014  {
15015  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15016  Utilities->CallLogPop(225);
15017  return(false);
15018  }
15019  }
15020 
15021 // check for same route as start element
15023  {
15024  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15025  Utilities->CallLogPop(226);
15026  return(false);
15027  }
15028 // check for a looping route
15029  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15030  {
15032  {
15033  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15034  Utilities->CallLogPop(1844);
15035  return(false);
15036  }
15037  }
15038 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15039 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15040 // and don't want to add it again
15041  if(StartSelectionRouteID > -1)
15042  {
15043  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15044  AutoSigsFlag, false))
15045  {
15046  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15047  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15048  {
15049  if(NewFailedPointsTVPos > -1)
15050  {
15051  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15052  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15053  " failed during route setting.");
15054  Utilities->CallLogPop(2488);
15055  return(false);
15056  }
15057  PointsChanged = true;
15058  }
15059  Utilities->CallLogPop(227);
15060  return(true);
15061  }
15062  else if(!Track->SuppressRouteFailMessage)
15063  {
15064  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15066  Utilities->CallLogPop(228);
15067  return(false);
15068  }
15069  }
15070  else
15071  {
15072 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15073 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15074 
15075 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15076 // note that a blank element will have XLinkPos set to -1
15077  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15078  {
15079  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15080  AutoSigsFlag, false))
15081  {
15082  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15083  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15084  {
15085  if(NewFailedPointsTVPos > -1)
15086  {
15087  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15088  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15089  " failed during route setting.");
15090  Utilities->CallLogPop(2490);
15091  return(false);
15092  }
15093  PointsChanged = true;
15094  }
15095  Utilities->CallLogPop(229);
15096  return(true);
15097  }
15098  else
15099  {
15101  {
15103  }
15104  Utilities->CallLogPop(230);
15105  return(false);
15106  }
15107  }
15108  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15109  {
15110  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15111  AutoSigsFlag, false))
15112  {
15113  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15114  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15115  {
15116  if(NewFailedPointsTVPos > -1)
15117  {
15118  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15119  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15120  " failed during route setting.");
15121  Utilities->CallLogPop(2492);
15122  return(false);
15123  }
15124  PointsChanged = true;
15125  }
15126  Utilities->CallLogPop(231);
15127  return(true);
15128  }
15129  else
15130  {
15132  {
15134  }
15135  Utilities->CallLogPop(232);
15136  return(false);
15137  }
15138  }
15139  // now start off in the best direction
15140  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15141  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15142  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15143  // unless new problems are found.
15144  if(StartElement1.XLinkPos == BestPos)
15145  {
15146  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15147  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15148  AutoSigsFlag, false))
15149  {
15150  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15151  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15152  {
15153  if(NewFailedPointsTVPos > -1)
15154  {
15155  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15156  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15157  " failed during route setting.");
15158  Utilities->CallLogPop(2494);
15159  return(false);
15160  }
15161  PointsChanged = true;
15162  }
15163  Utilities->CallLogPop(233);
15164  return(true);
15165  }
15166  else if(StartElement2.TrackVectorPosition > -1)
15167  {
15168  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15169  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15170  AutoSigsFlag, false))
15171  {
15172  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15173  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15174  {
15175  if(NewFailedPointsTVPos > -1)
15176  {
15177  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15178  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15179  " failed during route setting.");
15180  Utilities->CallLogPop(2496);
15181  return(false);
15182  }
15183  PointsChanged = true;
15184  }
15185  Utilities->CallLogPop(234);
15186  return(true);
15187  }
15188  }
15189  }
15190  else if(StartElement2.TrackVectorPosition > -1)
15191  {
15192  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15193  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15194  AutoSigsFlag, false))
15195  {
15196  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15197  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15198  {
15199  if(NewFailedPointsTVPos > -1)
15200  {
15201  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15202  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15203  " failed during route setting.");
15204  Utilities->CallLogPop(2498);
15205  return(false);
15206  }
15207  PointsChanged = true;
15208  }
15209  Utilities->CallLogPop(1857);
15210  return(true);
15211  }
15212  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15213  AutoSigsFlag, false))
15214  {
15215  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15216  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15217  {
15218  if(NewFailedPointsTVPos > -1)
15219  {
15220  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15221  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15222  " failed during route setting.");
15223  Utilities->CallLogPop(2500);
15224  return(false);
15225  }
15226  PointsChanged = true;
15227  }
15228  Utilities->CallLogPop(1858);
15229  return(true);
15230  }
15231  }
15232  else if(StartElement1.XLinkPos == (1 - BestPos))
15233  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15234  {
15235  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15236  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15237  AutoSigsFlag, false))
15238  {
15239  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15240  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15241  {
15242  if(NewFailedPointsTVPos > -1)
15243  {
15244  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15245  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15246  " failed during route setting.");
15247  Utilities->CallLogPop(2502);
15248  return(false);
15249  }
15250  PointsChanged = true;
15251  }
15252  Utilities->CallLogPop(1864);
15253  return(true);
15254  }
15255  }
15256  }
15258  {
15260  }
15261  Utilities->CallLogPop(235);
15262  return(false);
15263 }
15264 
15265 // ---------------------------------------------------------------------------
15266 
15267 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15268 {
15269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15270  if(PrefDirSize() == 0)
15271  {
15272  Utilities->CallLogPop(1704);
15273  return;
15274  }
15275  for(unsigned int x = 0; x < PrefDirSize(); x++)
15276  {
15277  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15278  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15279  {
15280  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15281  TempPrefDirElement.EXGraphicPtr);
15282  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15283  {
15284  if(x == 0)
15285  {
15286  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15287  TempPrefDirElement.EntryDirectionGraphicPtr);
15288  }
15289  if(x == (PrefDirSize() - 1))
15290  {
15291  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15292  TempPrefDirElement.EntryDirectionGraphicPtr);
15293  }
15294  }
15295  }
15296  }
15297 
15298  Utilities->CallLogPop(1705);
15299 }
15300 
15301 // ---------------------------------------------------------------------------
15302 
15303 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15304  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15305 /*
15306  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15307  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15308  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15309  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15310  Return false if any element (apart from RequiredPosition) is on an existing route.
15311  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15312 
15313  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15314  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15315  added during the function so as to leave it exactly as it was on entering, then return false).
15316  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15317  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15318  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15319  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15320  the route number that the searched-for element is the start of if any, and set to -1 if no
15321  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15322  this unit, together with the ConsecSignals and AutoSigsFlag flags.
15323  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15324  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15325 
15326  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15327  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15328  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15329  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15330  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15331  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15332  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15333  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15334  or if train on element (unless a bridge & train on different track).
15335  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15336  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15337  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15338  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15339  AutoSignals member set if AutoSigsFlag set, then return true.
15340  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15341 
15342  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15343  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15344  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15345  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15346  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15347  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15348  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15349 
15350  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15351  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15352 */
15353 
15354 {
15355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15356  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15357  AnsiString((short)AutoSigsFlag));
15358  int VectorCount = 0;
15359  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15360 
15361 // check for a fouled diagonal for first element. Added for v1.3.2
15362  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15363  {
15364  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15365  {
15366  for(int x = 0; x < VectorCount; x++)
15367  {
15368  SearchVector.erase(SearchVector.end() - 1);
15369  }
15370  Utilities->CallLogPop(2043);
15371  return(false);
15372  }
15373  }
15374  bool FirstPass = true;
15375 
15376  while(true)
15377  {
15378  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15379  {
15380  Track->LCFoundInAutoSigsRoute = true;
15381  }
15382  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15383  {
15384  for(int x = 0; x < VectorCount; x++)
15385  {
15386  SearchVector.erase(SearchVector.end() - 1);
15387  }
15388  Utilities->CallLogPop(1926);
15389  return(false);
15390  }
15391  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15392  {
15393  for(int x = 0; x < VectorCount; x++)
15394  {
15395  SearchVector.erase(SearchVector.end() - 1);
15396  }
15397  Utilities->CallLogPop(236);
15398  return(false);
15399  }
15400  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15401  // reached a valid signal that isn't the required position, user should always select the next
15402  // signal in a route when ConsecSignals is true so have to fail
15403  // won't affect recurive searches as for them the first pass element is always a point
15404  {
15405  for(int x = 0; x < VectorCount; x++)
15406  {
15407  SearchVector.erase(SearchVector.end() - 1);
15408  }
15409  Utilities->CallLogPop(237);
15410  return(false);
15411  }
15412  FirstPass = false;
15413  int NextPosition = PrefDirElement.Conn[XLinkPos];
15414  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15415  TPrefDirElement SearchElement(NextTrackElement);
15416  SearchElement.TrackVectorPosition = NextPosition;
15417  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15418  SearchElement.ELinkPos = NextELinkPos;
15419  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15420  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15421  int NextXLinkPos;
15422  if(SearchElement.ELinkPos == 0)
15423  {
15424  NextXLinkPos = 1;
15425  }
15426  if(SearchElement.ELinkPos == 1)
15427  {
15428  NextXLinkPos = 0;
15429  }
15430  if(SearchElement.ELinkPos == 2)
15431  {
15432  NextXLinkPos = 3;
15433  }
15434  if(SearchElement.ELinkPos == 3)
15435  {
15436  NextXLinkPos = 2;
15437  }
15438  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15439  {
15440  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15441 // note that may be buffers, continuation or gap
15442  SearchElement.XLinkPos = NextXLinkPos;
15443  }
15444 
15445 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
15446 
15447 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15448  for(unsigned int x = 0; x < SearchVector.size(); x++)
15449  {
15450  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15451  {
15452  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15453  // OK if a bridge & routes on different tracks
15454  {
15455  for(int x = 0; x < VectorCount; x++)
15456  {
15457  SearchVector.erase(SearchVector.end() - 1);
15458  }
15459  Utilities->CallLogPop(238);
15460  return(false);
15461  }
15462  }
15463  }
15464 
15465 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15466  TAllRoutes::TRouteElementPair SecondPair;
15468  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15469  if(RoutePair.first > -1)
15470  {
15471  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15472  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
15473  RoutePair.second).ELinkPos)))
15474  {
15475  // still OK if start of an expected route
15476  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
15477  {
15478  for(int x = 0; x < VectorCount; x++)
15479  {
15480  SearchVector.erase(SearchVector.end() - 1);
15481  }
15482  Utilities->CallLogPop(239);
15483  return(false); // only allow for start of an expected route
15484  }
15485  }
15486  }
15487  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15488  {
15489  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15490  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
15491  SecondPair.second).ELinkPos)))
15492  {
15493  // still OK if start of an expected route
15494  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
15495  {
15496  for(int x = 0; x < VectorCount; x++)
15497  {
15498  SearchVector.erase(SearchVector.end() - 1);
15499  }
15500  Utilities->CallLogPop(240);
15501  return(false); // only allow for start of an expected route
15502  }
15503  }
15504  }
15505 // check if a train on element, unless a bridge & train on different track
15506 // OK of same train as start element - no drop this
15507 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15508  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15509  {
15510  for(int x = 0; x < VectorCount; x++)
15511  {
15512  SearchVector.erase(SearchVector.end() - 1);
15513  }
15514  Utilities->CallLogPop(241);
15515  return(false);
15516  }
15517  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15518  {
15519  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
15520  {
15521  for(int x = 0; x < VectorCount; x++)
15522  {
15523  SearchVector.erase(SearchVector.end() - 1);
15524  }
15525  Utilities->CallLogPop(242);
15526  return(false);
15527  }
15528  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
15529  {
15530  for(int x = 0; x < VectorCount; x++)
15531  {
15532  SearchVector.erase(SearchVector.end() - 1);
15533  }
15534  Utilities->CallLogPop(243);
15535  return(false);
15536  }
15537  }
15538 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15539  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15540  {
15541  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15542  {
15543  for(int x = 0; x < VectorCount; x++)
15544  {
15545  SearchVector.erase(SearchVector.end() - 1);
15546  }
15547  Utilities->CallLogPop(244);
15548  return(false);
15549  }
15550  }
15551 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15552 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15553  bool InPrefDirFlag = false;
15554  PrefDirElement1 = BlankElement;
15555  PrefDirElement2 = BlankElement;
15556 
15557  bool FoundFlag;
15558  int PrefDirPos0 = -1;
15559  int PrefDirPos1 = -1;
15560  int PrefDirPos2 = -1;
15561  int PrefDirPos3 = -1;
15563  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15564  int PrefDirVecPos[4] =
15565  {
15566  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15567  };
15568  for(int x = 0; x < 4; x++)
15569  {
15570  int b = PrefDirVecPos[x];
15571  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15572  {
15573  InPrefDirFlag = true;
15574  if(PrefDirElement1.TrackVectorPosition == -1)
15575  {
15576  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15577  }
15578  else
15579  {
15580  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15581  }
15582  }
15583  }
15584  if(!InPrefDirFlag)
15585  {
15586  for(int x = 0; x < VectorCount; x++)
15587  {
15588  SearchVector.erase(SearchVector.end() - 1);
15589  }
15590  Utilities->CallLogPop(245);
15591  return(false);
15592  }
15593 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15594 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15595 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15597  {
15598  for(int x = 0; x < VectorCount; x++)
15599  {
15600  SearchVector.erase(SearchVector.end() - 1);
15601  }
15602  Utilities->CallLogPop(1690);
15603  return(false);
15604  }
15605 // check if found it
15606  if(SearchElement.TrackVectorPosition == RequiredPosition)
15607  {
15608 // need to ensure a signal/buffer/continuation
15609  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
15610  {
15611  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15613  for(int x = 0; x < VectorCount; x++)
15614  {
15615  SearchVector.erase(SearchVector.end() - 1);
15616  }
15617  Utilities->CallLogPop(246);
15618  return(false);
15619  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15620 
15621  if(AutoSigsFlag)
15622  {
15623  PrefDirElement1.AutoSignals = true;
15624  }
15625  PrefDirElement1.PrefDirRoute = true;
15627  {
15629  {
15630  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15632  }
15633  for(int x = 0; x < VectorCount; x++)
15634  {
15635  SearchVector.erase(SearchVector.end() - 1);
15636  }
15637  Utilities->CallLogPop(1928);
15638  return(false);
15639  }
15640  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15641  VectorCount++; // not really needed but include for tidyness
15642  TotalSearchCount++;
15643  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0
15644  {
15645  for(int x = 0; x < VectorCount; x++)
15646  {
15647  SearchVector.erase(SearchVector.end() - 1);
15648  }
15649  Utilities->CallLogPop(2522);
15650  return(false);
15651  }
15652  Utilities->CallLogPop(247);
15653  return(true);
15654  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15655 
15656 // check if a buffer or continuation (end of search on this leg if not found by now)
15657  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15658  {
15659  for(int x = 0; x < VectorCount; x++)
15660  {
15661  SearchVector.erase(SearchVector.end() - 1);
15662  }
15663  Utilities->CallLogPop(248);
15664  return(false);
15665  }
15666 // check if SearchVector exceeds a size of 150
15667  if(SearchVector.size() > 150)
15668  {
15669  for(int x = 0; x < VectorCount; x++)
15670  {
15671  SearchVector.erase(SearchVector.end() - 1);
15672  }
15673  Utilities->CallLogPop(1420);
15674  return(false);
15675  }
15676 //deal with failed points, added at v2.13.0
15677  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
15678  {
15679  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
15680  {
15681  SearchElement.XLinkPos = 1;
15682  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15683  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15684  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15685  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15686  }
15687  else
15688  {
15689  SearchElement.XLinkPos = 3;
15690  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15691  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15692  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15693  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15694  }
15695  }
15696  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
15697  {
15698  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
15699  {
15700  for(int x = 0; x < VectorCount; x++)
15701  {
15702  SearchVector.erase(SearchVector.end() - 1);
15703  }
15704  Utilities->CallLogPop(2514);
15705  return(false);
15706  }
15707  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
15708  {
15709  for(int x = 0; x < VectorCount; x++)
15710  {
15711  SearchVector.erase(SearchVector.end() - 1);
15712  }
15713  Utilities->CallLogPop(2515);
15714  return(false);
15715  }
15716  }
15717 // check if reached a non-failed leading point
15718  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
15719  {
15720 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15721  int SearchPos1 = SearchElement.Attribute + 1;
15722  int SearchPos2;
15723  if(SearchPos1 == 2)
15724  {
15725  SearchPos1++;
15726  }
15727  if(SearchPos1 == 1)
15728  {
15729  SearchPos2 = 3;
15730  }
15731  else
15732  {
15733  SearchPos2 = 1;
15734  }
15735  SearchElement.XLink = SearchElement.Link[SearchPos1];
15736  SearchElement.XLinkPos = SearchPos1;
15737  InPrefDirFlag = false;
15738  if(SearchElement.XLink == PrefDirElement1.XLink)
15739  {
15740  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15741  InPrefDirFlag = true;
15742  }
15743  else if(SearchElement.XLink == PrefDirElement2.XLink)
15744  {
15745  SearchElement = PrefDirElement2;
15746  InPrefDirFlag = true;
15747  }
15748 // push element with XLink set to position [SearchPos1] if on a PrefDir
15749  if(InPrefDirFlag)
15750  {
15751 // check for a fouled diagonal for leading point for XLinkPos == 1)
15752  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15753  {
15754  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15755  {
15756  for(int x = 0; x < VectorCount; x++)
15757  {
15758  SearchVector.erase(SearchVector.end() - 1);
15759  }
15760  Utilities->CallLogPop(249);
15761  return(false);
15762  }
15763  }
15764  if(AutoSigsFlag)
15765  {
15766  SearchElement.AutoSignals = true;
15767  }
15768  SearchElement.PrefDirRoute = true;
15769  SearchVector.push_back(SearchElement);
15770  VectorCount++;
15771  TotalSearchCount++;
15772 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15773  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15774  AutoSigsFlag, true))
15775  {
15777  {
15779  {
15780  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15782  }
15783  for(int x = 0; x < VectorCount; x++)
15784  {
15785  SearchVector.erase(SearchVector.end() - 1);
15786  }
15787  Utilities->CallLogPop(1929);
15788  return(false);
15789  }
15790  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
15791  {
15792  for(int x = 0; x < VectorCount; x++)
15793  {
15794  SearchVector.erase(SearchVector.end() - 1);
15795  }
15796  Utilities->CallLogPop(2523);
15797  return(false);
15798  }
15799  Utilities->CallLogPop(250);
15800  return(true);
15801  }
15802  else
15803  {
15804 // remove leading point with XLinkPos [1]
15805  SearchVector.erase(SearchVector.end() - 1);
15806  VectorCount--;
15807  }
15808  }
15809 // XLink set to position [SearchPos2]
15810  SearchElement.XLink = SearchElement.Link[SearchPos2];
15811  SearchElement.XLinkPos = SearchPos2;
15812  if(SearchElement.XLink == PrefDirElement1.XLink)
15813  {
15814  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15815  }
15816  else if(SearchElement.XLink == PrefDirElement2.XLink)
15817  {
15818  SearchElement = PrefDirElement2;
15819  }
15820  else // failed to find a valid exit from the point
15821  {
15822  for(int x = 0; x < VectorCount; x++)
15823  {
15824  SearchVector.erase(SearchVector.end() - 1);
15825  }
15826  Utilities->CallLogPop(251);
15827  return(false);
15828  }
15829 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15830  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15831  {
15832  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15833  {
15834  for(int x = 0; x < VectorCount; x++)
15835  {
15836  SearchVector.erase(SearchVector.end() - 1);
15837  }
15838  Utilities->CallLogPop(252);
15839  return(false);
15840  }
15841  }
15842 // push element with XLink set to position [SearchPos2]
15843  if(AutoSigsFlag)
15844  {
15845  SearchElement.AutoSignals = true;
15846  }
15847  SearchElement.PrefDirRoute = true;
15848  SearchVector.push_back(SearchElement);
15849  VectorCount++;
15850  TotalSearchCount++;
15851 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15852  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15853  AutoSigsFlag, true))
15854  {
15856  {
15858  {
15859  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15861  }
15862  for(int x = 0; x < VectorCount; x++)
15863  {
15864  SearchVector.erase(SearchVector.end() - 1);
15865  }
15866  Utilities->CallLogPop(1930);
15867  return(false);
15868  }
15869  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
15870  {
15871  for(int x = 0; x < VectorCount; x++)
15872  {
15873  SearchVector.erase(SearchVector.end() - 1);
15874  }
15875  Utilities->CallLogPop(2524);
15876  return(false);
15877  }
15878  Utilities->CallLogPop(1592);
15879  return(true);
15880  }
15881  else
15882  {
15883  for(int x = 0; x < VectorCount; x++)
15884  {
15885  SearchVector.erase(SearchVector.end() - 1);
15886  }
15887  Utilities->CallLogPop(253);
15888  return(false);
15889  }
15890  } // if leading point
15891 
15892 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15893  SearchElement = PrefDirElement1;
15894  if(AutoSigsFlag)
15895  {
15896  SearchElement.AutoSignals = true;
15897  }
15898  SearchElement.PrefDirRoute = true;
15899  SearchVector.push_back(SearchElement);
15900  VectorCount++;
15901  TotalSearchCount++;
15902  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15903  PrefDirElement = SearchElement;
15904  } // while(true)
15905 }
15906 
15907 // ---------------------------------------------------------------------------
15908 
15909 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15910 {
15911 /*
15912  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15913  and the new or extended route created from that. Hence action varies depending on whether
15914  it is a completely new route, or an extension of an existing route at the beginning or the end.
15915  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15916  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15917 
15918  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15919  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15920  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15921  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15922  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15923  is decremented;
15924  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15925  from the existing route, then enter the new route into the AllRoutesVector;
15926  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15927  then enter the new route into the AllRoutesVector.
15928 
15929  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15930  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15931  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15932  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15933  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15934  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15935  for the new route and return;
15936  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15937  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15938 
15939  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15940  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15941  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15942 
15943 */
15944  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15945  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15946  if(SearchVector.size() < 1)
15947  {
15948  Utilities->CallLogPop(254);
15949  return;
15950  }
15952  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15953  {
15954  Utilities->CallLogPop(255);
15955  return;
15956  }
15957  TAllRoutes::TLockedRouteClass LockedRouteObject;
15958 
15960  unsigned int TruncatePrefDirPosition = 0;
15961 
15962  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15963 /* if have ReqPosRouteID:
15964  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15965  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15966  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15967  the existing route, then enter the new route into the AllRoutesVector
15968  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15969  then enter the new route into the AllRoutesVector
15970 */
15971  {
15974  {
15975  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15976  x++) // start at 1 as first element already in SearchVector
15977  {
15979  }
15980  // note that route numbers in map adjusted when ReqPos route cleared
15982  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15983  // set during ClearRouteDuringRouteBuildingAt
15985  {
15988  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15989  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15990  }
15991  }
15993  {
15995  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15996  }
15998  {
15999  SearchVector.pop_back();
16000  }
16001  }
16002  if(StartSelectionRouteID > -1)
16003 /* if have StartSelectionRouteID:
16004  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16005  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16006  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16007  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16008  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16009 */
16010  {
16012  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16013  {
16016  {
16017  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16018  for(unsigned int x = 0; x < SearchVector.size(); x++)
16019  {
16021  RouteNumber, GetFixedSearchElementAt(3, x));
16022  // find & store locked route truncate position in PrefDirVector for later use
16024  {
16025  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16026  {
16027  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16028  }
16029  }
16030  }
16032  {
16033  throw Exception("Error - failed to validate extended route for preferred route");
16034  }
16037  if(!AutoSigsFlag)
16038  {
16039  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16040  }
16041  // now add the reinstated locked route if required and set signals accordingly
16043  {
16044  LockedRouteObject.RouteNumber = RouteNumber;
16045  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16046  // now reset the signals for the locked route
16047  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16048  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16049  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16050  {
16051  // return all signals to red in route section to be truncated
16052  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16053  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16054  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16055  {
16056  TrackElement.Attribute = 0;
16057  Track->PlotSignal(10, TrackElement, Display);
16058  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16059  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16060  }
16061  }
16062  }
16063  AllRoutes->CheckMapAndRoutes(1); // test
16064  Utilities->CallLogPop(256);
16065  return;
16066  }
16068  {
16071  RouteElement.AutoSignals = true;
16072  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16073  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16074  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16075  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16076  }
16077  }
16078  else
16079  {
16081  }
16082 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16083 // AllRoutesVector hence nothing to do here
16084  }
16085  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16086  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16087  {
16088  throw Exception("Error - failed to validate single route for preferred route");
16089  }
16090  AllRoutes->StoreOneRoute(1, this);
16091  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16092  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16093  if(!AutoSigsFlag)
16094  {
16095  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16096  }
16097  AllRoutes->CheckMapAndRoutes(2); // test
16098  Utilities->CallLogPop(257);
16099 }
16100 
16101 // ---------------------------------------------------------------------------
16102 
16103 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16104 {
16105 /*
16106  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16107  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16108  & ensure signal/buffers/continuation.
16109  Note that can't select ConsecSignalsRoute for non-preferred routes.
16110  Check if train on element & disallow.
16111  Set default values for retained parameters:-
16112  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16113  StartSelectionRouteID = route that selection starts in if there is one;
16114 
16115  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16116  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16117  validity. This is just for safety reasons, the PrefDir values aren't used.
16118  StartElement1 & 2 are set to these PrefDirelements.
16119 
16120  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16121 
16122  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16123  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16124  blank StartElement2 (only want to use the route element), then return true.
16125  Check if adjacent to start or end of an existing route & disallow if so.
16126  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16127  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16128  SetRemainingSearchVectorValues().
16129  Finally add the required element to the SearchVector & return true.
16130 
16131 */
16132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16133  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16134  ClearRoute();
16135  int TrackVectorPosition;
16136  TTrackElement TrackElement;
16137  TPrefDirElement FirstElement, LastElement;
16138 
16139  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16140  {
16141  Utilities->CallLogPop(258);
16142  return(false);
16143  }
16144  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16145  {
16146  if(!Callon)
16147  {
16148  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16149  }
16150 // makes later adjacent route checks too complicated
16151  Utilities->CallLogPop(259);
16152  return(false);
16153  }
16154  if(Track->IsLCAtHV(21, HLoc, VLoc))
16155  {
16156  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16157  Utilities->CallLogPop(1910);
16158  return(false);
16159  }
16160 // check if selected a train & disallow if so
16161  if(TrackElement.TrainIDOnElement > -1)
16162  {
16163  if(!Callon)
16164  {
16165  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16166  }
16167  Utilities->CallLogPop(260);
16168  return(false);
16169  }
16170 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16171  TPrefDirElement PrefDirElement;
16172  int LockedVectorNumber;
16173 
16174  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16175  {
16176  if(!Callon)
16177  {
16178  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16179  }
16180  Utilities->CallLogPop(261);
16181  return(false);
16182  }
16183  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16184  {
16185  if(!Callon)
16186  {
16187  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16188  }
16189  Utilities->CallLogPop(262);
16190  return(false);
16191  }
16193 // AdjacentStartRouteNumber = -1;
16194  StartRoutePosition = TrackVectorPosition;
16195 // StartRouteSelectPosition = TrackVectorPosition;
16196 
16197  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16198  TPrefDirElement PrefDirElement2(TrackElement);
16199 
16200  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16201  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16202  TPrefDirElement BlankElement;
16203 
16204  PrefDirElement1.ELinkPos = 0;
16205  PrefDirElement1.XLinkPos = 1;
16206  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16207  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16208  if(!(PrefDirElement1.EntryExitNumber()))
16209  {
16210  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16211  // no need for bridge check as bridge selections not allowed
16212  }
16213  PrefDirElement1.CheckCount = 9;
16214  PrefDirElement2.ELinkPos = 1;
16215  PrefDirElement2.XLinkPos = 0;
16216  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16217  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16218  if(!(PrefDirElement2.EntryExitNumber()))
16219  {
16220  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16221  }
16222  PrefDirElement2.CheckCount = 9; // both now set
16223 
16224 // set StartElements to the above PrefDirElements
16225  StartElement1 = PrefDirElement1;
16226  StartElement2 = PrefDirElement2;
16227 
16228 // no PrefDir check needed as doesn't need to be in a PrefDir
16229 
16230 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16232  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16233 
16234  if(RoutePair.first > -1)
16235  {
16236  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16237  {
16238  if(!Callon)
16239  {
16240  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16241  }
16242  Utilities->CallLogPop(263);
16243  return(false);
16244  }
16245  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16246  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16247  {
16248  if(!Callon)
16249  {
16250  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16251  }
16252  Utilities->CallLogPop(264);
16253  return(false);
16254  }
16255  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16256  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16257  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16258  {
16259  if(!Callon)
16260  {
16261  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16262  }
16263  Utilities->CallLogPop(265);
16264  return(false);
16265  }
16266  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16268  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16269  StartElement2 = BlankElement; // only use the route element
16271  Utilities->CallLogPop(266);
16272  return(true); // all retained values set
16273  }
16274 
16275  else // selection not in an existing route
16276  {
16277 // check if it's adjacent to start of an an existing route,
16278  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16279  {
16280  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16281  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16282  {
16283  if(!Callon)
16284  {
16285  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16286  }
16287  Utilities->CallLogPop(267);
16288  return(false);
16289  }
16290  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16291  {
16292  if(!Callon)
16293  {
16294  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16295  }
16296  Utilities->CallLogPop(268);
16297  return(false);
16298  }
16299  }
16300 // check if it's adjacent to end of an an existing route,
16301  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16302  {
16304  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16305  {
16306  if(!Callon)
16307  {
16308  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16309  }
16310  Utilities->CallLogPop(269);
16311  return(false);
16312  }
16313  }
16314  // not in a route or adjacent to start or end of a route
16315  // in this case reset all variable values to -1 & CheckCount to 4
16316  StartElement1.ELink = -1;
16317  StartElement1.ELinkPos = -1;
16318  StartElement1.XLink = -1;
16319  StartElement1.XLinkPos = -1;
16320  StartElement1.EXNumber = -1;
16321  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
16322  StartElement2 = BlankElement;
16323  SearchVector.push_back(StartElement1);
16324  Utilities->CallLogPop(270);
16325  return(true);
16326  }
16327 }
16328 
16329 // ---------------------------------------------------------------------------
16330 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16331 
16332 /*
16333  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16334 
16335  Declare the following integers:-
16336  EndPosition - TrackVectorPosition for the selection;
16337  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16338  Check if selection is a valid track element and set EndPosition.
16339  Cancel if select original start element, then check that not points, bridge or crossover.
16340  Check & fail if a train is present at the selection.
16341  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16342  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16343  No check needed for selection in EveryPrefDir.
16344  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16345  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16346  as don't need it if in a route.
16347  Check if selection adj to start or end of a route and disallow.
16348  Fail if select same route as starting route, though should already have failed earlier if this is so.
16349 
16350  If there's a StartSelectionRouteID then StartElement1 will be set to
16351  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16352  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16353  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16354  to add the new route to the AllRoutesVectorPtr.
16355  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16356  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16357  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16358  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16359  the search vector values and return.
16360  If not returned yet then have failed to find the required element so return false with no message.
16361 
16362 */
16363 
16364 {
16365 // get EndPosition
16366  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16367  AnsiString(VLoc));
16368  int EndPosition;
16369  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16370 
16371  TotalSearchCount = 0;
16372  ReqPosRouteID = IDInt(-1); // for not used
16373  TTrackElement TrackElement;
16374  TPrefDirElement BlankElement;
16376 
16377  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16378  {
16379  Utilities->CallLogPop(271);
16380  return(false);
16381  }
16382 // EndPosition = EndSelectPosition;
16383 // cancel selection if on original start element
16384  if(EndPosition == StartRoutePosition)
16385  {
16386  Utilities->CallLogPop(272);
16387  return(false);
16388  }
16389  if(Track->IsLCAtHV(22, HLoc, VLoc))
16390  {
16391  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
16392  Utilities->CallLogPop(1911);
16393  return(false);
16394  }
16395  if((TrackElement.TrackType == Points) && !Callon)
16396  {
16397  if(!Callon)
16398  {
16399  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16400  }
16401 // makes later adjacent route checks too complicated
16402  Utilities->CallLogPop(273);
16403  return(false);
16404  }
16405  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16406  {
16407  if(!Callon)
16408  {
16409  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16410  }
16411 // makes later adjacent route checks too complicated
16412  Utilities->CallLogPop(1861);
16413  return(false);
16414  }
16415 // check if train on element
16416  if(TrackElement.TrainIDOnElement > -1)
16417  {
16418  if(!Callon)
16419  {
16420  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
16421  }
16422  Utilities->CallLogPop(274);
16423  return(false);
16424  }
16425 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
16426 // check passed)
16427  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16428  TPrefDirElement EndElement2(TrackElement);
16429 
16430  EndElement1.TrackVectorPosition = EndPosition;
16431  EndElement2.TrackVectorPosition = EndPosition;
16432  EndElement1.ELinkPos = 0;
16433  EndElement1.XLinkPos = 1;
16434  EndElement1.ELink = EndElement1.Link[0];
16435  EndElement1.XLink = EndElement1.Link[1];
16436  if(!(EndElement1.EntryExitNumber()))
16437  {
16438  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
16439  }
16440  EndElement1.CheckCount = 9;
16441  EndElement2.ELinkPos = 1;
16442  EndElement2.XLinkPos = 0;
16443  EndElement2.ELink = EndElement2.Link[1];
16444  EndElement2.XLink = EndElement2.Link[0];
16445  if(!(EndElement2.EntryExitNumber()))
16446  {
16447  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
16448  }
16449  EndElement2.CheckCount = 9; // both now set
16450 
16451 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
16452 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
16453 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
16454 
16455  if(EndElement1.HLoc >= StartElement1.HLoc)
16456  {
16458  SearchLimitHighH = EndElement1.HLoc + 15;
16459  }
16460  else
16461  {
16462  SearchLimitLowH = EndElement1.HLoc - 15;
16464  }
16465  if(EndElement1.VLoc >= StartElement1.VLoc)
16466  {
16468  SearchLimitHighV = EndElement1.VLoc + 15;
16469  }
16470  else
16471  {
16472  SearchLimitLowV = EndElement1.VLoc - 15;
16474  }
16475 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
16476  check & TotalSearchCounts check
16477  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
16478  {
16479  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
16480  Utilities->CallLogPop(1694);
16481  return false;
16482  }
16483 */
16484 // don't need EveryPrefDir check for NonPreferredRoute
16485 
16486 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
16487 // bool InRoute = false;
16489  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16490 
16491  if(RoutePair.first > -1)
16492  {
16493  if(RoutePair.second != 0) // not first element in existing route so no good
16494  {
16495  if(!Callon)
16496  {
16497  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
16498  }
16499  Utilities->CallLogPop(275);
16500  return(false);
16501  }
16502  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
16503 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
16504  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
16505  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
16506  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16507  {
16508  if(!Callon)
16509  {
16510  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
16511  }
16512  Utilities->CallLogPop(276);
16513  return(false);
16514  }
16515  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
16516  EndElement2 = BlankElement; // only need the route element
16517  EndPosition = EndElement1.TrackVectorPosition;
16518  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
16519  }
16520 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
16521  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16522  {
16523  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
16524  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
16525 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16526 // && (AdjPosition != StartRoutePosition))
16527  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16528  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16529  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
16530  {
16531  if(!Callon)
16532  {
16533  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
16534  }
16535  Utilities->CallLogPop(277);
16536  return(false);
16537  }
16538 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
16539 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
16540  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
16541  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16542  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
16543  (AdjPosition != StartRoutePosition))
16544  {
16545  if(!Callon)
16546  {
16547  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
16548  }
16549  Utilities->CallLogPop(278);
16550  return(false);
16551  }
16552 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
16554  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
16555  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
16556  {
16557  if(!Callon)
16558  {
16559  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
16560  }
16561  Utilities->CallLogPop(279);
16562  return(false);
16563  }
16564  }
16565 
16566 // check for same route as start element
16568  {
16569  if(!Callon)
16570  {
16571  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16572  }
16573  Utilities->CallLogPop(280);
16574  return(false);
16575  }
16576 // check for a looping route
16577  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16578  {
16580  {
16581  if(!Callon)
16582  {
16583  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16584  }
16585  Utilities->CallLogPop(1845);
16586  return(false);
16587  }
16588  }
16589 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16590 // so search from this element.
16591 
16592  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16593 
16594  if(StartSelectionRouteID > -1)
16595  {
16596  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
16597  {
16599  if(PointsToBeChanged(0, NewFailedPointsTVPos))
16600  {
16601  if(NewFailedPointsTVPos > -1)
16602  {
16603  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
16604  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
16605  " failed during route setting.");
16606  Utilities->CallLogPop(2504);
16607  return(false);
16608  }
16609  PointsChanged = true;
16610  }
16611  Utilities->CallLogPop(281);
16612  return(true);
16613  }
16614  else
16615  {
16616  if(!Callon && !Track->SuppressRouteFailMessage)
16617  {
16619  }
16620  Utilities->CallLogPop(282);
16621  return(false);
16622  }
16623  }
16624  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16625  // search on the 2 ways out of the element, which has to be a 2-ended element
16626  {
16627 // check if selection adjacent to start element and if so use that
16628  if(SearchVector.at(0).Conn[0] == EndPosition)
16629  {
16630  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
16631  {
16633  if(PointsToBeChanged(1, NewFailedPointsTVPos))
16634  {
16635  if(NewFailedPointsTVPos > -1)
16636  {
16637  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
16638  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
16639  " failed during route setting.");
16640  Utilities->CallLogPop(2506);
16641  return(false);
16642  }
16643  PointsChanged = true;
16644  }
16645  Utilities->CallLogPop(283);
16646  return(true);
16647  }
16648  else
16649  {
16650  if(!Callon && !Track->SuppressRouteFailMessage)
16651  {
16653  }
16654  Utilities->CallLogPop(284);
16655  return(false);
16656  }
16657  }
16658  else if(SearchVector.at(0).Conn[1] == EndPosition)
16659  {
16660  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
16661  {
16663  if(PointsToBeChanged(2, NewFailedPointsTVPos))
16664  {
16665  if(NewFailedPointsTVPos > -1)
16666  {
16667  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
16668  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
16669  " failed during route setting.");
16670  Utilities->CallLogPop(2508);
16671  return(false);
16672  }
16673  PointsChanged = true;
16674  }
16675  Utilities->CallLogPop(285);
16676  return(true);
16677  }
16678  else
16679  {
16680  if(!Callon && !Track->SuppressRouteFailMessage)
16681  {
16683  }
16684  Utilities->CallLogPop(286);
16685  return(false);
16686  }
16687  }
16688  // now start off in the best direction
16689  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16690 
16691  if(SearchVector.at(0).Config[BestPos] != End)
16692  {
16693  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16694  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
16695  {
16697  if(PointsToBeChanged(3, NewFailedPointsTVPos))
16698  {
16699  if(NewFailedPointsTVPos > -1)
16700  {
16701  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
16702  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
16703  " failed during route setting.");
16704  Utilities->CallLogPop(2510);
16705  return(false);
16706  }
16707  PointsChanged = true;
16708  }
16709  Utilities->CallLogPop(287);
16710  return(true);
16711  }
16712  }
16713  if(SearchVector.at(0).Config[1 - BestPos] != End)
16714  {
16715  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16716  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
16717  {
16719  if(PointsToBeChanged(4, NewFailedPointsTVPos))
16720  {
16721  if(NewFailedPointsTVPos > -1)
16722  {
16723  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
16724  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
16725  " failed during route setting.");
16726  Utilities->CallLogPop(2512);
16727  return(false);
16728  }
16729  PointsChanged = true;
16730  }
16731  Utilities->CallLogPop(288);
16732  return(true);
16733  }
16734  }
16735  }
16736  if(!Callon && !Track->SuppressRouteFailMessage)
16737  {
16739  }
16740  Utilities->CallLogPop(289);
16741  return(false);
16742 }
16743 
16744 // ---------------------------------------------------------------------------
16745 
16746 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
16747 /*
16748  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16749  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16750  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16751  Keep a count of entries in SearchVector during the current function call, so that this number can be
16752  erased for an unproductive branch search.
16753  First check (within the loop) whether XLink leads to an End & return false if so.
16754  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16755  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16756  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16757  train on element (unless a bridge & train on different track), or if element
16758  fouls an existing diagonal route (except if element is a leading point - these checked later).
16759  Then check if found required element. If so save it & return true.
16760  If not the required element check if buffer or continuation, & if so erase all searchvector
16761  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16762  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16763  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16764  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16765  When return true have 8 items from CheckCount established, only waiting for EXNumber
16766 */
16767 {
16768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16769  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16770  int VectorCount = 0;
16771 
16772 // check for a fouled diagonal for first element. Added for v1.3.2
16773  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16774  (CurrentTrackElement.Link[XLinkPos] == 9))
16775  {
16776  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16777  {
16778  for(int x = 0; x < VectorCount; x++)
16779  {
16780  SearchVector.erase(SearchVector.end() - 1);
16781  }
16782  Utilities->CallLogPop(2044);
16783  return(false);
16784  }
16785  }
16786  while(true)
16787  {
16788  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16789  {
16790  for(int x = 0; x < VectorCount; x++)
16791  {
16792  SearchVector.erase(SearchVector.end() - 1);
16793  }
16794  Utilities->CallLogPop(1927);
16795  return(false);
16796  }
16797  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16798  {
16799  for(int x = 0; x < VectorCount; x++)
16800  {
16801  SearchVector.erase(SearchVector.end() - 1);
16802  }
16803  Utilities->CallLogPop(290);
16804  return(false);
16805  }
16806  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16807  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16808  TPrefDirElement SearchElement(NextTrackElement);
16809  SearchElement.TrackVectorPosition = NextPosition;
16810  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16811  SearchElement.ELinkPos = NextELinkPos;
16812  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16813  int NextXLinkPos;
16814  if(SearchElement.ELinkPos == 0)
16815  {
16816  NextXLinkPos = 1;
16817  }
16818  if(SearchElement.ELinkPos == 1)
16819  {
16820  NextXLinkPos = 0;
16821  }
16822  if(SearchElement.ELinkPos == 2)
16823  {
16824  NextXLinkPos = 3;
16825  }
16826  if(SearchElement.ELinkPos == 3)
16827  {
16828  NextXLinkPos = 2;
16829  }
16830  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16831  {
16832  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16833  // but may be buffers, continuation or gap
16834  SearchElement.XLinkPos = NextXLinkPos;
16835  }
16836 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16837 // can't set XLink or XLinkPos yet if the element is a leading point.
16838 
16839 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16840  for(unsigned int x = 0; x < SearchVector.size(); x++)
16841  {
16842  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16843  {
16844  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16845  // OK if it's a bridge & routes on different tracks
16846  {
16847  for(int x = 0; x < VectorCount; x++)
16848  {
16849  SearchVector.erase(SearchVector.end() - 1);
16850  }
16851  Utilities->CallLogPop(291);
16852  return(false);
16853  }
16854  }
16855  }
16856 
16857 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16858  TAllRoutes::TRouteElementPair SecondPair;
16860  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16861  if(RoutePair.first > -1)
16862  {
16863  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16864  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16865  RoutePair.second).ELinkPos)))
16866  {
16867  // still OK if start of an expected route
16868  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16869  {
16870  for(int x = 0; x < VectorCount; x++)
16871  {
16872  SearchVector.erase(SearchVector.end() - 1);
16873  }
16874  Utilities->CallLogPop(292);
16875  return(false); // only allow for start of an expected route
16876  }
16877  }
16878  }
16879  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16880  {
16881  // OK if it's a bridge & routes on different tracks
16882  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16883  SecondPair.second).ELinkPos)))
16884  {
16885  // still OK if start of an expected route
16886  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16887  {
16888  for(int x = 0; x < VectorCount; x++)
16889  {
16890  SearchVector.erase(SearchVector.end() - 1);
16891  }
16892  Utilities->CallLogPop(293);
16893  return(false); // only allow for start of an expected route
16894  }
16895  }
16896  }
16897 // check if a train on element, unless a bridge & train on different track
16898 // OK of same train as start element - no, drop this
16899 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16900  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16901  {
16902  for(int x = 0; x < VectorCount; x++)
16903  {
16904  SearchVector.erase(SearchVector.end() - 1);
16905  }
16906  Utilities->CallLogPop(294);
16907  return(false);
16908  }
16909  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16910  {
16911  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16912  {
16913  for(int x = 0; x < VectorCount; x++)
16914  {
16915  SearchVector.erase(SearchVector.end() - 1);
16916  }
16917  Utilities->CallLogPop(295);
16918  return(false);
16919  }
16920  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16921  {
16922  for(int x = 0; x < VectorCount; x++)
16923  {
16924  SearchVector.erase(SearchVector.end() - 1);
16925  }
16926  Utilities->CallLogPop(296);
16927  return(false);
16928  }
16929  }
16930 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16931  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16932  {
16933  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16934  {
16935  for(int x = 0; x < VectorCount; x++)
16936  {
16937  SearchVector.erase(SearchVector.end() - 1);
16938  }
16939  Utilities->CallLogPop(297);
16940  return(false);
16941  }
16942  }
16943 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16944 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16945 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16947  {
16948  for(int x = 0; x < VectorCount; x++)
16949  {
16950  SearchVector.erase(SearchVector.end() - 1);
16951  }
16952  Utilities->CallLogPop(1689);
16953  return(false);
16954  }
16955 // check if found it
16956  if(SearchElement.TrackVectorPosition == RequiredPosition)
16957  {
16958  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16959  {
16960  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16961  {
16962  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16963  }
16964  else
16965  {
16966  SearchElement.XLinkPos = 1;
16967  }
16968 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16969  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16970  }
16971  SearchVector.push_back(SearchElement);
16972  VectorCount++; // not really needed but include for tidyness
16973  TotalSearchCount++;
16974  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
16975  {
16976  for(int x = 0; x < VectorCount; x++)
16977  {
16978  SearchVector.erase(SearchVector.end() - 1);
16979  }
16980  Utilities->CallLogPop(2525);
16981  return(false);
16982  }
16983  Utilities->CallLogPop(298);
16984  return(true);
16985  }
16986 // Not the required element - check if a buffer or continuation
16987  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16988  {
16989  for(int x = 0; x < VectorCount; x++)
16990  {
16991  SearchVector.erase(SearchVector.end() - 1);
16992  }
16993  Utilities->CallLogPop(299);
16994  return(false);
16995  }
16996 // check if SearchVector exceeds a size of 150
16997  if(SearchVector.size() > 150)
16998  {
16999  for(int x = 0; x < VectorCount; x++)
17000  {
17001  SearchVector.erase(SearchVector.end() - 1);
17002  }
17003  Utilities->CallLogPop(1421);
17004  return(false);
17005  }
17006 //deal with failed points, added at v2.13.0
17007  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17008  {
17009  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17010  {
17011  SearchElement.XLinkPos = 1;
17012  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17013  }
17014  else
17015  {
17016  SearchElement.XLinkPos = 3;
17017  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17018  }
17019  }
17020  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17021  {
17022  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17023  {
17024  for(int x = 0; x < VectorCount; x++)
17025  {
17026  SearchVector.erase(SearchVector.end() - 1);
17027  }
17028  Utilities->CallLogPop(2533);
17029  return(false);
17030  }
17031  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17032  {
17033  for(int x = 0; x < VectorCount; x++)
17034  {
17035  SearchVector.erase(SearchVector.end() - 1);
17036  }
17037  Utilities->CallLogPop(2534);
17038  return(false);
17039  }
17040  }
17041 
17042 // check if reached a non-failed leading point
17043  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17044  { //added !Failed condition at v2.13.0 to exclude failed points
17045 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17046  int SearchPos1 = SearchElement.Attribute + 1;
17047  int SearchPos2;
17048  if(SearchPos1 == 2)
17049  {
17050  SearchPos1++;
17051  }
17052  if(SearchPos1 == 1)
17053  {
17054  SearchPos2 = 3;
17055  }
17056  else
17057  {
17058  SearchPos2 = 1;
17059  }
17060 // push element with XLink set to position [SearchPos1]
17061  SearchElement.XLink = SearchElement.Link[SearchPos1];
17062  SearchElement.XLinkPos = SearchPos1;
17063 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17064  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17065  {
17066  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17067  {
17068  for(int x = 0; x < VectorCount; x++)
17069  {
17070  SearchVector.erase(SearchVector.end() - 1);
17071  }
17072  Utilities->CallLogPop(300);
17073  return(false);
17074  }
17075  }
17076  SearchVector.push_back(SearchElement);
17077  VectorCount++;
17078  TotalSearchCount++;
17079 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17080 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17081 // recursive search as has to be a TTrackElement for non-preferred route searches
17082  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17083  {
17084  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17085  {
17086  for(int x = 0; x < VectorCount; x++)
17087  {
17088  SearchVector.erase(SearchVector.end() - 1);
17089  }
17090  Utilities->CallLogPop(2526);
17091  return(false);
17092  }
17093  Utilities->CallLogPop(301);
17094  return(true);
17095  }
17096  else
17097  {
17098 // remove leading point with XLinkPos [SearchPos1]
17099  SearchVector.erase(SearchVector.end() - 1);
17100  VectorCount--;
17101 // push element with XLink set to position [SearchPos2]
17102  SearchElement.XLink = SearchElement.Link[SearchPos2];
17103  SearchElement.XLinkPos = SearchPos2;
17104 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17105  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17106  {
17107  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17108  {
17109  for(int x = 0; x < VectorCount; x++)
17110  {
17111  SearchVector.erase(SearchVector.end() - 1);
17112  }
17113  Utilities->CallLogPop(302);
17114  return(false);
17115  }
17116  }
17117  SearchVector.push_back(SearchElement);
17118  VectorCount++;
17119  TotalSearchCount++;
17120 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17121  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17122  {
17123  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17124  {
17125  for(int x = 0; x < VectorCount; x++)
17126  {
17127  SearchVector.erase(SearchVector.end() - 1);
17128  }
17129  Utilities->CallLogPop(2527);
17130  return(false);
17131  }
17132  Utilities->CallLogPop(303);
17133  return(true);
17134  }
17135  else
17136  {
17137  for(int x = 0; x < VectorCount; x++)
17138  {
17139  SearchVector.erase(SearchVector.end() - 1);
17140  }
17141  Utilities->CallLogPop(304);
17142  return(false);
17143  }
17144  }
17145  } // if leading point
17146 
17147 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17148 // ready for next element on route
17149  SearchVector.push_back(SearchElement);
17150  VectorCount++;
17151  TotalSearchCount++;
17152  CurrentTrackElement = SearchElement;
17153  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17154  } // while(true)
17155 }
17156 
17157 // ---------------------------------------------------------------------------
17158 
17160 
17161 /*
17162  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17163  having all values set (since not necessarily on PrefDirs).
17164  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17165  (if it was the start), so these are checked first and set if necessary. All elements now have
17166  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17167  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17168  to set the route colour and direction graphics.
17169 */
17170 
17171 {
17172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17173  if(SearchVector.size() == 0)
17174  {
17175  throw Exception("Error, SearchVector empty");
17176  }
17177 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17178 // hence need to examine and update it if necessary
17179  TPrefDirElement SecondElement;
17180 
17181  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17182  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17183  // need above check or SecondElement will fail
17184  {
17185  SecondElement = SearchVector.at(1);
17186  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17187  for(int x = 0; x < 4; x++)
17188  {
17189  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17190  {
17191  if(SearchVector.at(0).XLink == -1) // i.e. not set
17192  {
17193  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17194  SearchVector.at(0).XLinkPos = x;
17195  }
17196  int ELinkPos;
17197  if(SearchVector.at(0).XLinkPos == 0)
17198  {
17199  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17200  }
17201  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17202  if(SearchVector.at(0).XLinkPos == 1)
17203  {
17204  ELinkPos = 0;
17205  }
17206  if(SearchVector.at(0).XLinkPos == 2)
17207  {
17208  ELinkPos = 3;
17209  }
17210  if(SearchVector.at(0).XLinkPos == 3)
17211  {
17212  ELinkPos = 2;
17213  }
17214  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17215  {
17216  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17217  SearchVector.at(0).ELinkPos = ELinkPos;
17218  }
17219  break; // no point going any further
17220  }
17221  }
17222  }
17223  for(unsigned int x = 0; x < SearchVector.size(); x++)
17224  {
17225  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17226 // set EXNumber
17227  if(!(SearchVector.at(x).EntryExitNumber()))
17228  {
17229  throw Exception("Error in EntryExitNumber 3");
17230  }
17231  SearchVector.at(x).CheckCount++;
17232 // all values now incorporated
17233  }
17234 
17235  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17236 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17237 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17238  Utilities->CallLogPop(305);
17239 }
17240 
17241 // ---------------------------------------------------------------------------
17242 
17244 
17245 /*
17246  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17247  AutoSigsRoute.
17248  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17249  beginning or the end.
17250  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17251  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17252  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17253  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17254  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17255  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17256  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17257 
17258  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17259  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17260  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17261  route at the start.
17262 
17263  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17264  for the new route and return.
17265 */
17266 
17267 {
17268  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17269  AnsiString(ReqPosRouteID.GetInt()));
17270  if(SearchVector.size() < 1)
17271  {
17272  Utilities->CallLogPop(306);
17273  return;
17274  }
17275  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17276  if(!ValidatePrefDir(6))
17277  {
17278  Utilities->CallLogPop(307);
17279  return;
17280  }
17281  TAllRoutes::TLockedRouteClass LockedRouteObject;
17282 
17284  unsigned int TruncatePrefDirPosition = 0;
17285 
17286  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17287 /* if have ReqPosRouteID:
17288  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17289  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17290  then enter the new route into the AllRoutesVector
17291 */
17292  {
17294  {
17295  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17296  x++) // start at 1 as first element already in SearchVector
17297  {
17299  }
17300  // note that route numbers in map adjusted when ReqPos route cleared
17302  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17303  // set during ClearRouteDuringRouteBuildingAt)
17305  {
17308  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17309  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17310  }
17311  }
17313  {
17314  SearchVector.pop_back();
17315  }
17316  }
17317  if(StartSelectionRouteID > -1)
17318 /* if have StartSelectionRouteID:
17319  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17320  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17321 */
17322  {
17324  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17325  {
17327  {
17328  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17329  for(unsigned int x = 0; x < SearchVector.size(); x++)
17330  {
17332  RouteNumber, GetFixedSearchElementAt(7, x));
17333  // find & store locked route truncate position in PrefDirVector for later use
17335  {
17336  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
17337  {
17338  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17339  }
17340  }
17341  }
17343  {
17344  throw Exception("Failed to validate extended route for nonpreferred route");
17345  }
17348  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17349  // now add the reinstated locked route if required and set signals accordingly
17350  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17351  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17352  // that I haven't thought of
17354  {
17355  LockedRouteObject.RouteNumber = RouteNumber;
17356  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17357  // now reset the signals for the locked route
17358  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17359  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17360  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17361  {
17362  // return all signals to red in route section to be truncated
17363  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17364  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17365  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17366  {
17367  TrackElement.Attribute = 0;
17368  Track->PlotSignal(11, TrackElement, Display);
17369  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17370  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17371  }
17372  }
17373  }
17374  AllRoutes->CheckMapAndRoutes(3); // test
17375  Utilities->CallLogPop(308);
17376  return;
17377  }
17378  }
17379  else
17380  {
17382  }
17383 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17384 // hence nothing to do here
17385  }
17386  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
17387  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
17388  {
17389  throw Exception("Failed to validate single route for nonpreferred route");
17390  }
17391  AllRoutes->StoreOneRoute(2, this);
17392  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
17393  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
17394  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
17395  AllRoutes->CheckMapAndRoutes(4); // test
17396  Utilities->CallLogPop(309);
17397 }
17398 
17399 // ---------------------------------------------------------------------------
17400 
17401 void TOneRoute::SetRoutePoints(int Caller) const
17402 /*
17403  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
17404  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
17405  when they were created.
17406 */
17407 {
17408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
17409  if(!PrefDirVector.empty())
17410  {
17411  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17412  {
17413  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
17414  {
17415  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
17416  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
17417  }
17418  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
17419  {
17420  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
17421  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
17422  }
17423  }
17424  }
17425  Utilities->CallLogPop(327);
17426 }
17427 
17428 // ---------------------------------------------------------------------------
17429 
17430 void TOneRoute::SetRouteSignals(int Caller) const
17431 /* Used for new train additions in AddTrain and in route setting
17432  Set the signals as follows:-
17433  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
17434  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
17435  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
17436  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
17437  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
17438  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
17439  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
17440  of the foregoing are found but there is a further forward linked forward route then the function returns false with
17441  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
17442 
17443  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
17444  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
17445  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
17446  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
17447  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
17448  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
17449  as a green signal.
17450 */
17451 {
17452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
17453  if(!PrefDirVector.empty())
17454  {
17455  // get target Attribute value, check first if there is a forward linked route
17456  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
17457  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
17458  int ForwardLinkedRouteNumber, Attribute = 0;
17459  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17460  // Note that LastElement can't be points but can be linked to points
17461  {
17462  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
17463  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17464  {
17465  if(ForwardLinkedRouteNumber > -1)
17466  {
17467  int NextForwardLinkedRouteNumber = -1;
17468  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
17469  Attribute)))
17470  {
17471  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
17472  }
17473  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
17474  // Attribute = 3, else if find signal (other than a ground signal with Attribute > 0 [added at v2.14.0]) then Attribute = (signal attribute + 1) (or
17475  // same as signal Attribute if ground signal with Attribute > 0) up to a max value of 3. All these return true, if find a forward linked
17476  // route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
17477  }
17478  }
17479  }
17480  int RouteNumber;
17481  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
17482  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
17483  if(RouteType != TAllRoutes::NoRoute)
17484  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
17485  {
17486  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
17487  }
17488  }
17489  Utilities->CallLogPop(1720);
17490 }
17491 
17492 // ---------------------------------------------------------------------------
17493 
17494 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
17495 {
17496  //true if at any point in SearchVector points have to be changed,
17497  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
17498  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
17499  NewFailedPointsTVPos = -1; //default value for no new failure
17500  bool PointsChanged = false;
17501  if(!SearchVector.empty())
17502  {
17503  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
17504  {
17505  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
17506  //check for an existing failed point where needs to change to make the route
17507  int Attr = TE.Attribute;
17508  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
17509  {
17510  if(Attr == 1) //currently set to diverge
17511  {
17512  //here add new failure possibility at v2.13.0
17513  if(Utilities->FailureMode != FNil)
17514  {
17515  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17516  {
17518  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17519  IFE.TVPos = NewFailedPointsTVPos;
17520  TE.Failed = true;
17521  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17523  TE.SpeedLimit01 = 10; //values while failed
17524  TE.SpeedLimit23 = 10;
17525  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17526  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17527  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17528  //set repair time, random value in minutes between 10 and 179
17529  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
17530  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17531  IFE.RepairTime = RepairTime;
17533  Track->FailedPointsVector.push_back(IFE);
17534  Utilities->CallLogPop(1717);
17535  return(true); //return so only allow one failure per route
17536  }
17537  }
17538  PointsChanged = true; //this is used for setting the flash time
17539  }
17540  }
17541  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
17542  {
17543  if(Attr == 0) //currently set to go straight
17544  {
17545  //here add failure possibility at v2.13.0
17546  if(Utilities->FailureMode != FNil)
17547  {
17548  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17549  {
17551  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17552  IFE.TVPos = NewFailedPointsTVPos;
17553  TE.Failed= true;
17554  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17556  TE.SpeedLimit01 = 10; //values while failed
17557  TE.SpeedLimit23 = 10;
17558  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17559  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17560  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17561  //set repair time, random value in minutes between 10 and 179
17562  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
17563  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17564  IFE.RepairTime = RepairTime;
17566  Track->FailedPointsVector.push_back(IFE);
17567  Utilities->CallLogPop(1718);
17568  return(true); //only allow one failure per route
17569  }
17570  }
17571  PointsChanged = true;
17572  }
17573  }
17574  }
17575  }
17576  Utilities->CallLogPop(1719);
17577  return(PointsChanged);
17578 }
17579 
17580 // ---------------------------------------------------------------------------
17581 
17582 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
17583 /*
17584  Works forward through the route until finds:-
17585  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17586  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
17587  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
17588  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17589  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
17590  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
17591  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
17592  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17593  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
17594 */
17595 {
17596  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
17597  Attribute = 0;
17598  NextForwardLinkedRouteNumber = -1;
17599  for(unsigned int x = 0; x < PrefDirSize(); x++)
17600  {
17601  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
17602  if(PrefDirVector.at(x).TrackType == Bridge)
17603  {
17604  if(PrefDirVector.at(x).XLinkPos < 2)
17605  {
17606  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17607  }
17608  else
17609  {
17610  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17611  }
17612  }
17613  if(TrainID != -1)
17614  {
17615  Utilities->CallLogPop(328);
17616  return(true);
17617  }
17618  if(PrefDirVector.at(x).TrackType == Buffers)
17619  {
17620  Attribute = 1;
17621  Utilities->CallLogPop(329);
17622  return(true);
17623  }
17624  if(PrefDirVector.at(x).TrackType == Continuation)
17625  {
17626  Attribute = 3;
17627  Utilities->CallLogPop(330);
17628  return(true);
17629  }
17630  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17631  {
17632  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17633  {
17634  Attribute = 0;
17635  Utilities->CallLogPop(1950);
17636  return(true);
17637  }
17638  }
17639  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
17640  {
17641  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
17642  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
17643  {
17644  Attribute++;
17645  }
17646  if(Attribute > 3)
17647  {
17648  Attribute = 3;
17649  }
17650  Utilities->CallLogPop(331);
17651  return(true);
17652  }
17653  if(x == PrefDirSize() - 1)
17654  {
17655  TPrefDirElement LastElement = PrefDirVector.at(x);
17656  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17657  {
17658  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
17659  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17660  {
17661  Attribute = 0;
17662  Utilities->CallLogPop(332);
17663  return(false);
17664  }
17665  }
17666  }
17667  }
17668  Utilities->CallLogPop(333);
17669  return(true);
17670 }
17671 
17672 // ---------------------------------------------------------------------------
17673 
17674 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
17675 /*
17676  This function is only called by TAllRoutes::SetAllRearwardsSignals.
17677 
17678  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17679  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17680  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17681  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17682  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17683  a route.
17684 
17685  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17686  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17687  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
17688  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
17689  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17690  reference. If no train is found before the beginning of the route is reached the function returns true
17691 
17692  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
17693  and the next rearwards signal becomes yellow, although it's the first in the route
17694 */
17695 {
17696  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
17697  AnsiString(PrefDirVectorStartPosition));
17698  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
17699  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
17700 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
17701 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
17702  bool SkipContinuationAndBufferAttributeChange = false;
17703 
17704  if(!PrefDirVector.empty())
17705  {
17706  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
17707  {
17708  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17709  if(PrefDirPtr->TrackType == Bridge)
17710  {
17711  if(PrefDirPtr->XLinkPos < 2)
17712  {
17713  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17714  }
17715  else
17716  {
17717  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17718  }
17719  }
17720  if(TrainID != -1)
17721  {
17722  SkipContinuationAndBufferAttributeChange = true;
17723  break;
17724  }
17725  }
17726 
17729  {
17730  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17731  AutoSigVectorIT++)
17732  {
17733  if(!AllRoutes->AllRoutesVector.empty())
17734  {
17735  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17736  {
17737  SkipContinuationAndBufferAttributeChange = true;
17738  break;
17739  }
17740  }
17741  }
17742  }
17744  {
17745  SkipContinuationAndBufferAttributeChange = true;
17746  }
17747  if(!SkipContinuationAndBufferAttributeChange)
17748  {
17749  if(PrefDirVector.back().TrackType == Buffers)
17750  {
17751  Attribute = 1; // treat buffer as red signal
17752  }
17753  if(PrefDirVector.back().TrackType == Continuation)
17754  {
17755  Attribute = 3; // treat continuation as a green signal
17756  }
17757  }
17758  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17759  {
17760  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17761  if(PrefDirPtr->TrackType == Bridge)
17762  {
17763  if(PrefDirPtr->XLinkPos < 2)
17764  {
17765  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17766  }
17767  else
17768  {
17769  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17770  }
17771  }
17772  if(TrainID != -1)
17773  {
17774  Utilities->CallLogPop(334);
17775  return(false);
17776  }
17777  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17778  // the attribute to 0 so first signal behind the LC is red
17779  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17780  {
17781  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17782  {
17783  Attribute = 0;
17784  }
17785  }
17786 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17787 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17788  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17789  {
17790  if((!AllRoutes->RouteBackTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17791  PrefDirPtr->PrefDirRoute)
17792  {
17793 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17794 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17795  int LockedVecNum = 0; //not used
17796  TPrefDirElement DummyPrefDir; //not used
17797  bool KeepAttributeAt0ForLockedRoute = false;
17798  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17799  LockedVecNum))
17800  {
17801  Attribute = 0;
17802  KeepAttributeAt0ForLockedRoute = true;
17803  }
17804 //end of v2.9.2 addition
17805 
17806 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
17807  bool NotGroundSignal = false;
17808  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
17809  {
17810  NotGroundSignal = true;
17811  }
17812 
17813  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
17814  {
17815  Attribute = 0; //stays at 0
17816  }
17817 
17818  if(Attribute < 3)
17819  {
17820  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17821  }
17822  else
17823  {
17824  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17825  }
17826  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17827  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17828  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17829  {
17830  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17831  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17832  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17833  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17834  }
17835  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
17836  { //if groundsignal attrib is 0 then do need to increment
17837  Attribute++; //this is for the next signal rearwards, not the current one
17838  }
17839 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
17840  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
17841  }
17842  }
17843  }
17844  }
17845  Utilities->CallLogPop(335);
17846  return(true);
17847 }
17848 
17849 // ---------------------------------------------------------------------------
17850 
17851 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17852 /*
17853  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17854  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17855  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17856  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17857  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17858  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17859  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17860  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17861 */
17862 {
17863  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17864  "," + AnsiString((short)PrefDirRoute));
17865  bool ElementInRoute = false;
17866  bool MovingTrainOccupyingRoute = false;
17867  unsigned int TruncatePDElementPos; //the selected PD position to truncate to (could be from the back or the front)//added at v2.15.0
17868  enum {NoTruncate, BackTruncate, FrontTruncate, FullTruncate} TruncateType;
17869  TruncateType = NoTruncate;
17871 
17872  for(unsigned int b = 0; b < PrefDirSize(); b++)
17873  {
17874  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17875  {
17876  TruncatePDElementPos = b;
17877  ElementInRoute = true;
17878  break;
17879  }
17880  }
17881  if(!ElementInRoute)
17882  {
17883  ReturnFlag = NotInRoute;
17884  Utilities->CallLogPop(336);
17885  return;
17886  }
17887 
17888  //now find whether back, front or full truncate //added at v2.15.0
17889  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate
17890  {
17891  if(TruncatePDElementPos == 0)
17892  {
17893  TruncateType = FullTruncate;
17894  }
17895  else
17896  {
17897  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
17898  if(TempElement.Config[TempElement.XLinkPos] == Signal)
17899  {
17900  TruncateType = FrontTruncate;
17901  }
17902  else
17903  {
17904  TruncateType = BackTruncate;
17906 
17907  }
17908  }
17909  }
17910  else // == PrefDirSize() - 1
17911  {
17912  TruncateType = BackTruncate;
17914  }
17915 
17916 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
17917 
17918  if(TruncateType == BackTruncate) //added at v2.15.0
17919  {
17920  for(int b = PrefDirSize() - 1; b >= 0; b--)
17921  {
17922  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17923  if(PrefDirVector.at(b).TrackType == Bridge)
17924  {
17925  if(PrefDirVector.at(b).XLinkPos < 2)
17926  {
17927  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17928  }
17929  else
17930  {
17931  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17932  }
17933  }
17934  if(TrainID != -1)
17935  {
17936  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
17937  {
17938  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
17939  }
17940  }
17941  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17942  {
17943  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17944  ReturnFlag = InRouteFalse;
17946  Utilities->CallLogPop(1941);
17947  return;
17948  }
17949  if(b == int(TruncatePDElementPos))
17950  {
17951  break; // OK found truncate element & no flashing LC in front
17952  }
17953  }
17954  }
17955  else if(TruncateType == FrontTruncate)//front/full truncate //added at v2.15.0
17956  {
17957  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
17958  {
17959  int TrainID = Track->TrackElementAt(1556, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17960  if(PrefDirVector.at(b).TrackType == Bridge)
17961  {
17962  if(PrefDirVector.at(b).XLinkPos < 2)
17963  {
17964  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17965  }
17966  else
17967  {
17968  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17969  }
17970  }
17971  if(TrainID != -1)
17972  {
17973  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
17974  {
17975  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
17976  }
17977  }
17978  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17979  {
17980  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
17981  ReturnFlag = InRouteFalse;
17983  Utilities->CallLogPop(2571);
17984  return;
17985  }
17986  if(b == TruncatePDElementPos)
17987  {
17988  break; // OK found truncate element & no flashing LC behind
17989  }
17990  }
17991  }
17992  else //FullTruncate) //added at v2.15.0
17993  {
17994  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
17995  {
17996  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17997  if(PrefDirVector.at(b).TrackType == Bridge)
17998  {
17999  if(PrefDirVector.at(b).XLinkPos < 2)
18000  {
18001  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18002  }
18003  else
18004  {
18005  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18006  }
18007  }
18008  if(TrainID != -1)
18009  {
18010  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
18011  {
18012  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18013  }
18014  }
18015  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18016  {
18017  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
18018  ReturnFlag = InRouteFalse;
18020  Utilities->CallLogPop(2572);
18021  return;
18022  }
18023  }
18024  }
18025 
18026  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
18027  {
18028  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
18029  ReturnFlag = InRouteFalse;
18031  Utilities->CallLogPop(338);
18032  return;
18033  }
18034  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
18035  {
18036  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
18037  ReturnFlag = InRouteFalse;
18039  Utilities->CallLogPop(339);
18040  return;
18041  }
18042 
18043  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
18044  {
18045  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
18046  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18047  {
18048  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18049  {
18050  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18051  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18052  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18053  ReturnFlag = InRouteFalse;
18055  Utilities->CallLogPop(340);
18056  return;
18057  }
18058  }
18059  else
18060  {
18061  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18062  {
18063  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
18064  ReturnFlag = InRouteFalse;
18066  Utilities->CallLogPop(341);
18067  return;
18068  }
18069  }
18070  }
18071 
18072  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
18073  {
18074  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
18075  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18076  {
18077  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18078  {
18079  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18080  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18081  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18082  ReturnFlag = InRouteFalse;
18084  Utilities->CallLogPop(2573);
18085  return;
18086  }
18087  }
18088  else //red route
18089  {
18090  if(TruncatePDElementPos > 0)
18091  {
18092  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
18093  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18094  {
18095  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
18096  ReturnFlag = InRouteFalse;
18098  Utilities->CallLogPop(2574);
18099  return;
18100  }
18101  }
18102  }
18103  }
18104 
18105  else if(TruncatePDElementPos == 0) //full truncate
18106  {
18107  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
18108  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
18109  {
18110  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
18111  {
18112  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18113  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18114  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18115  ReturnFlag = InRouteFalse;
18117  Utilities->CallLogPop(2575);
18118  return;
18119  }
18120  }
18121  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
18122  {
18123  if(TempElement.TrackType == Bridge)
18124  {
18125  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
18126  ReturnFlag = InRouteFalse;
18128  Utilities->CallLogPop(2576);
18129  return;
18130  }
18131  }
18132  }
18133 
18134  int ThisRouteNumber;
18136 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
18137 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
18138 
18139 // check if part of this route already locked & disallow if so
18140  if(!(AllRoutes->LockedRouteVector.empty()))
18141  {
18143  {
18144  if(LRVIT->RouteNumber == ThisRouteNumber)
18145  {
18146  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
18147  ReturnFlag = InRouteFalse;
18149  Utilities->CallLogPop(749);
18150  return;
18151  }
18152  }
18153  }
18154 
18155  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
18156  if(TruncateType == BackTruncate) //is within 3 running signals on this or linked rearwards routes -m this is a PDElement position
18157  {
18158  LookBackwardsFromHere = TruncatePDElementPos;
18159  }
18160 
18161 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
18162  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
18163  int FrontPosition;
18164 
18165  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
18166  // RouteLockingRequired only checks for trains approaching
18167  {
18170  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
18171  L"Warning!", MB_YESNO | MB_ICONWARNING);
18172  TrainController->BaseTime = TDateTime::CurrentDateTime();
18174  if(button == IDNO)
18175  {
18176  ReturnFlag = InRouteTrue; // still return true even though don't act on it
18178  Utilities->CallLogPop(342);
18179  return;
18180  }
18181  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
18182  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
18183  TAllRoutes::TLockedRouteClass LockedRoute;
18184  bool ExistingLockedRouteModified = false;
18185  LockedRoute.RouteNumber = ThisRouteNumber;
18186  if(TruncateType == BackTruncate)
18187  {
18188  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18189  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18190  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18191  }
18192  else if(TruncateType == FrontTruncate)
18193  {
18194  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18195  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18196  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
18197  }
18198  else //FullTruncate
18199  {
18200  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18201  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18202  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18203  }
18204 
18205  LockedRoute.LockStartTime = TrainController->TTClockTime;
18206 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
18207 // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
18208  if(!AllRoutes->LockedRouteVector.empty())
18209  {
18210  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
18211  LRVIT++)
18212  {
18213  if(LRVIT->RouteNumber == ThisRouteNumber)
18214  {
18215  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
18216  LRVIT->LockStartTime = LockedRoute.LockStartTime;
18217  ExistingLockedRouteModified = true;
18218  }
18219  }
18220  }
18221  if(!ExistingLockedRouteModified)
18222  {
18223  AllRoutes->LockedRouteVector.push_back(LockedRoute);
18224  }
18225  if(TruncateType == BackTruncate)
18226  {
18227  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
18228  RearPosition = TruncatePDElementPos;
18229  FrontPosition = PrefDirSize() - 1;
18230  }
18231  else if(TruncateType == FrontTruncate)
18232  {
18233  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
18234  RearPosition = 0;
18235  FrontPosition = TruncatePDElementPos;
18236  }
18237  else //FullTruncate
18238  {
18239  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
18240  RearPosition = 0;
18241  FrontPosition = PrefDirSize() - 1;
18242  }
18243 // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
18244  for(int c = FrontPosition; c >= RearPosition; c--)
18245  {
18246  // return all signals to red in route section to be truncated
18247  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
18248  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
18249  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18250  {
18251  TrackElement.Attribute = 0;
18252  Track->PlotSignal(2, TrackElement, Display);
18253  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18254  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18255  }
18256  }
18257 // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
18258  ReturnFlag = InRouteTrue;
18259  }
18260  else //route locking not required
18261  {
18262  if(TruncateType == BackTruncate)
18263  {
18264  RearPosition = TruncatePDElementPos;
18265  FrontPosition = PrefDirSize() - 1;
18266  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
18267  }
18268  else if(TruncateType == FrontTruncate)
18269  {
18270  RearPosition = 0;
18271  FrontPosition = TruncatePDElementPos;
18272  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
18273  }
18274  else
18275  {
18276  RearPosition = 0;
18277  FrontPosition = PrefDirSize() - 1;
18278  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
18279  }
18280 
18281  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
18282  //into adjacent red or green routes if there are any (after the truncation/removal)
18283 
18284  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18285  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
18286 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
18287 
18288  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
18289  {
18290  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
18291  ReturnFlag = InRouteTrue;
18292  }
18293 
18294  if(LastPDElement.AutoSignals)
18295  {
18296  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
18297  }
18298  }
18299 
18300  AllRoutes->CheckMapAndRoutes(5); // test
18301  ReturnFlag = InRouteTrue;
18303  Utilities->CallLogPop(344);
18304 }
18305 
18306 // ---------------------------------------------------------------------------
18307 
18309 {
18310 /*
18311 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
18312 signal.
18313 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
18314  but a new route that is created TO a signal - that signal becomes part of the new route.
18315 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
18316 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
18317  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
18318  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
18319  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
18320  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
18321  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
18322 */
18323 
18324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
18325  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
18326  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
18327  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
18328  {
18329  Utilities->CallLogPop(2578);
18330  return;
18331  }
18332  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
18333  int RouteColour;
18334  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
18335  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
18336  {
18337  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
18338  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
18339  { //found a linked forward route
18340  //check if signal behind this route has been removed from the blue route
18341  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
18342  { //signal needs to be added at start of this linked route
18343 
18344  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
18345  if(RouteColour == 1) //red route
18346  {
18347  NewRedFirstPDElement = LastPDElement;
18348  NewRedFirstPDElement.AutoSignals = false;
18349  NewRedFirstPDElement.PrefDirRoute = false;
18350  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
18351  NewRedFirstPDElement.IsARoute = true;
18352  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
18353  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
18354  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
18355  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
18356  {
18357  if(R2MMIt->second.first == int(x))
18358  {
18359  R2MMIt->second.second++;
18360  }
18361  }
18362  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
18363  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18364  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
18365  }
18366  else if(RouteColour == 2) //green route
18367  {
18368  NewGreenFirstPDElement = LastPDElement;
18369  NewGreenFirstPDElement.AutoSignals = false;
18370  NewGreenFirstPDElement.PrefDirRoute = true;
18371  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
18372  NewGreenFirstPDElement.IsARoute = true;
18373  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
18374  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
18375  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
18376  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
18377  {
18378  if(R2MMIt->second.first == int(x))
18379  {
18380  R2MMIt->second.second++;
18381  }
18382  }
18383  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
18384  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18385  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
18386  }
18387  }
18388  break; //no point looking any further
18389  }
18390  }
18391 
18392 //check if there's a linked rearward route missing a signal and if so add it
18393  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
18394  {
18395  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
18396  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
18397  { //found a linked rearward route
18398  //check if signal in front of this route has been removed from the blue route
18399  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
18400  { //signal needs to be added at end of this linked route
18401 
18402  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
18403  if(RouteColour == 1) //red route
18404  {
18405  NewRedLastPDElement = FirstPDElement;
18406  NewRedLastPDElement.AutoSignals = false;
18407  NewRedLastPDElement.PrefDirRoute = false;
18408  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
18409  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
18410  //can use this as adding to the end of the route
18411  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18412  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
18413  }
18414  else if(RouteColour == 2) //green route
18415  {
18416  NewGreenLastPDElement = FirstPDElement;
18417  NewGreenLastPDElement.AutoSignals = false;
18418  NewGreenLastPDElement.PrefDirRoute = true;
18419  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
18420  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
18421  //can use this as adding to the end of the route
18422  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18423  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
18424  }
18425  }
18426  break; //no point looking any further
18427  }
18428  }
18429  Utilities->CallLogPop(2579);
18430 }
18431 
18432 // ---------------------------------------------------------------------------
18433 
18435 /*
18436  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
18437  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
18438  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
18439  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
18440  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
18441  the route colours.
18442 */
18443 {
18444  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
18445  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
18447  int RouteNumber;
18448  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
18449  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
18450  //these added at v2.15.0
18451  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18452  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
18453 
18454  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
18455  {
18456  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
18457  {
18458  if(PrefDirVector.at(x).TrackType == SignalPost)
18459  {
18460  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
18461  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
18462  }
18463  }
18464  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
18465 // already set all signals to red in route so start at start of route for further rearwards signal setting
18466  }
18467  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
18468  {
18469  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
18470  }
18471 
18472  if(LastPDElement.AutoSignals) //added at v2.15.0
18473  {
18474  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
18475  }
18476 
18477  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
18478  AllRoutes->CheckMapAndRoutes(9); // test
18479  TrainController->BaseTime = TDateTime::CurrentDateTime();
18481  Utilities->CallLogPop(345);
18482  return;
18483 }
18484 
18485 // ---------------------------------------------------------------------------
18486 
18487 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18488 /*
18489  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
18490 */
18491 {
18492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
18493  AnsiString((short)PrefDirRoute));
18494  if(SearchVector.empty())
18495  {
18496  Utilities->CallLogPop(1149);
18497  return;
18498  }
18499  for(unsigned int b = 0; b < SearchVector.size(); b++)
18500  {
18503  PrefDirRoute);
18504  }
18505  Utilities->CallLogPop(346);
18506 }
18507 
18508 // ---------------------------------------------------------------------------
18509 
18510 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18511 /*
18512  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
18513  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
18514  TOneRoute.
18515 */
18516 {
18517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
18518  AnsiString((short)PrefDirRoute));
18519  RouteFlash.RouteFlashVector.clear();
18520  TRouteFlashElement RouteFlashElement;
18521 
18522  for(unsigned int b = 0; b < SearchVector.size(); b++)
18523  {
18524  int H = GetFixedSearchElementAt(11, b).HLoc;
18525  int V = GetFixedSearchElementAt(12, b).VLoc;
18527  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
18528  RouteFlashElement.HLoc = H;
18529  RouteFlashElement.VLoc = V;
18531  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
18532  }
18533  Utilities->CallLogPop(348);
18534 }
18535 
18536 // ---------------------------------------------------------------------------
18537 
18538 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
18539 {
18540  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
18541  if(!PrefDirVector.empty())
18542  {
18543  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18544  {
18545  int H = PrefDirPtr->HLoc;
18546  int V = PrefDirPtr->VLoc;
18547  // check for any LCs that are closed to trains & set the flash values and store in the vector
18548  if(Track->IsLCAtHV(39, H, V))
18549  {
18550  if(Track->IsLCBarrierUpAtHV(0, H, V))
18551  {
18552  Track->LCChangeFlag = true;
18553  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
18554  CLC.HLoc = H;
18555  CLC.VLoc = V;
18557  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
18560  if(PrefDirRoute)
18561  {
18562  CLC.TypeOfRoute = 1;
18563  }
18564  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
18565  Track->ChangingLCVector.push_back(CLC);
18566  }
18567  }
18568  }
18569  }
18570  Utilities->CallLogPop(1948);
18571 }
18572 
18573 // ---------------------------------------------------------------------------
18574 
18576 /*
18577  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18578  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
18579  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18580  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18581 */
18582 {
18583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
18584  if(!OverlayPlotted)
18585  {
18586  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18587  {
18588  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18589  {
18590  continue;
18591  }
18592  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
18593  Display->Update();
18594  }
18595  OverlayPlotted = true;
18596  }
18597  Utilities->CallLogPop(349);
18598 }
18599 
18600 // ---------------------------------------------------------------------------
18601 
18603 /*
18604  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18605  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
18606  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18607  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18608 */
18609 {
18610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
18611  if(OverlayPlotted)
18612  {
18613  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18614  {
18615  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18616  {
18617  continue;
18618  }
18619  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
18620  Display->Update();
18621  }
18622  OverlayPlotted = false;
18623  }
18624  Utilities->CallLogPop(350);
18625 }
18626 
18627 // ---------------------------------------------------------------------------
18628 
18629 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
18630 {
18631 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
18632 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
18633 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
18634 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
18635 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
18636 messages, and allocate a repair time similar to points)
18637 */
18638 
18639  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
18640  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
18641  {
18642  Utilities->CallLogPop(2528);
18643  return(false);
18644  }
18645  bool FirstSignalFound = false;
18646  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
18647  {
18648  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
18649 //check for a failed point where needs to change to make the route
18650 //shouldn't be any but check to be safe
18651  int Attr = TE.Attribute;
18652  if(PDVIt->TrackType == Points)
18653  {
18654  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
18655  {
18656  if(Attr == 1) //currently set to diverge
18657  {
18658  if(TE.Failed)
18659  {
18660  Utilities->CallLogPop(2529);
18661  return(false); //return without further checking
18662  }
18663  }
18664  }
18665  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
18666  {
18667  if(Attr == 0) //currently set to go straight
18668  {
18669  if(TE.Failed)
18670  {
18671  Utilities->CallLogPop(2530);
18672  return(false); //return without further checking
18673  }
18674  }
18675  }
18676  }
18677  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
18678  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
18679  //the search vector)
18680  int XLinkPosition = PDVIt->XLinkPos;
18681  if(PDVIt->XLinkPos == -1)
18682  {
18683  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
18684  {
18685  for(int x = 0; x < 4; x++)
18686  {
18687  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
18688  {
18689  XLinkPosition = x;
18690  break;
18691  }
18692  }
18693  }
18694  else
18695  {
18696  Utilities->CallLogPop(2549);
18697  return(false); //no point going any further
18698  }
18699  }
18700  if(XLinkPosition > -1) //should be by now but be safe
18701  {
18702  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
18703  {
18704  FirstSignalFound = true; //the first signal doesn't change aspect
18705  continue;
18706  }
18707  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
18708  {
18709 /*
18710  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
18711  {
18712  continue; //ground signals don't fail
18713  }
18714 */
18715  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
18716  {
18718  IFE.TVPos = PDVIt->TrackVectorPosition;
18719  TE.Failed = true;
18720  TE.Attribute = 0; //stop aspect
18721  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
18722  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
18723  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
18724  " failed when changing aspect.\nTrains can only pass under signaller control.");
18725  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18726  //set repair time, random value in minutes between 10 and 179
18727  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18728  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18729  IFE.RepairTime = RepairTime;
18731  Track->FailedSignalsVector.push_back(IFE);
18733  int RouteNumber; //not used
18734  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
18735  { // 0 for LinkPos ok as a signal so only one track
18736  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
18737  }
18738  Utilities->CallLogPop(2535);
18739  return(true); //return so only allow one failure per route
18740  }
18741  }
18742  }
18743  }
18744  Utilities->CallLogPop(2531);
18745  return(false);
18746 }
18747 
18748 // ---------------------------------------------------------------------------
18749 // ---------------------------------------------------------------------------
18750 
18751 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
18752 {
18753  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
18754  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18755  {
18756  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
18757  }
18758  Utilities->CallLogPop(120);
18759  return(AllRoutesVector.at(At));
18760 }
18761 
18762 // ---------------------------------------------------------------------------
18763 
18765 {
18766  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
18767  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18768  {
18769  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
18770  }
18771  Utilities->CallLogPop(121);
18772  return(AllRoutesVector.at(At));
18773 }
18774 
18775 // ---------------------------------------------------------------------------
18776 
18777 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
18778 /*
18779  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
18780 */
18781 {
18782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
18783  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18784  {
18785  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
18786  }
18787  Utilities->CallLogPop(351);
18788 }
18789 
18790 // ---------------------------------------------------------------------------
18791 
18792 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
18793 {
18794  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
18795  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18796  {
18797  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
18798  }
18799  Utilities->CallLogPop(1706);
18800 }
18801 
18802 // ---------------------------------------------------------------------------
18803 
18804 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
18805 /*
18806  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
18807  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
18808  Messages are given in TruncateRoute. If successful the route is truncated at and including
18809  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
18810  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
18811  length (train length).
18812 */
18813 {
18814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
18815  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
18816  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18817  {
18818  TTruncateReturnType ReturnFlag;
18819 // used in SetRearwardsSignalsReturnFalseForTrain (called by TruncateRoute) to skip continuation & buffer attribute change
18820  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
18821  if(ReturnFlag == NotInRoute)
18822  {
18823  continue;
18824  }
18825  else if(ReturnFlag == InRouteTrue)
18826  {
18827  Utilities->CallLogPop(352);
18828  return(true);
18829  }
18830  else if(ReturnFlag == InRouteFalse)
18831  {
18832  Utilities->CallLogPop(353);
18833  return(false);
18834  }
18835  }
18836  Utilities->CallLogPop(354);
18837  return(false);
18838 }
18839 
18840 // ---------------------------------------------------------------------------
18841 
18842 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
18843 /*
18844  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
18845  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
18846 */
18847 {
18848  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
18849  AnsiString(LinkPos));
18850  if(TrackVectorPosition == -1) // allows for continuation entries & exits
18851  {
18852  Utilities->CallLogPop(355);
18853  return(false);
18854  }
18855  THVPair Route2MultiMapKeyPair;
18856 
18857  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
18858  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
18859  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18860  TRoute2MultiMapIterator Route2MultiMapIterator;
18861 
18862  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
18863  {
18864  Utilities->CallLogPop(356);
18865  return(false);
18866  }
18867  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
18868  {
18869  Utilities->CallLogPop(1422);
18870  return(true);
18871  }
18872  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
18873  {
18874  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18875 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18876 // realised after writing this that can't be points as would have been covered above, but leave anyway
18877  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
18878  Route2MultiMapIterator->second.second);
18879  EntryLinkPos = PrefDirElement1.ELinkPos;
18880  ExitLinkPos = PrefDirElement1.XLinkPos;
18881  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18882  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18883  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
18884  {
18885  Utilities->CallLogPop(357);
18886  return(true);
18887  }
18888  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
18889  {
18890  Utilities->CallLogPop(358);
18891  return(true);
18892  }
18893  }
18894  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
18895  {
18896  Utilities->CallLogPop(1423);
18897  return(true);
18898  }
18899  Utilities->CallLogPop(363);
18900  return(false); // none found
18901 }
18902 
18903 // ---------------------------------------------------------------------------
18904 
18905 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
18906  Graphics::TBitmap* &EntryDirectionGraphicPtr)
18907 /*
18908  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
18909  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
18910  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
18911  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
18912  for replotting of AutoSigsRoutes.
18913 */
18914 {
18915  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
18916  AnsiString(LinkPos));
18917  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
18918  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
18919  if(TrackVectorPosition == -1)
18920  {
18921  Utilities->CallLogPop(364);
18922  return(NoRoute); // allows for continuation entries & exits
18923  }
18924  THVPair Route2MultiMapKeyPair;
18925 
18926  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
18927  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
18928  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18929  TRoute2MultiMapIterator Route2MultiMapIterator;
18930 
18931  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18932  {
18933  Utilities->CallLogPop(365);
18934  return(NoRoute); // none found
18935  }
18936  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18937  {
18938  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18939 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18940  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
18941  Route2MultiMapIterator->second.second);
18942  EntryLinkPos = PrefDirElement1.ELinkPos;
18943  ExitLinkPos = PrefDirElement1.XLinkPos;
18944  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18945  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18946  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
18947  {
18948  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
18949  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
18950  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
18951  {
18952  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
18953  }
18954  if(PrefDirElement1.AutoSignals)
18955  {
18956  Utilities->CallLogPop(366);
18957  return(AutoSigsRoute);
18958  }
18959  else
18960  {
18961  Utilities->CallLogPop(367);
18962  return(NotAutoSigsRoute);
18963  }
18964  }
18965  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
18966  {
18967  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
18968  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
18969  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
18970  {
18971  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
18972  }
18973  if(PrefDirElement1.AutoSignals)
18974  {
18975  Utilities->CallLogPop(368);
18976  return(AutoSigsRoute);
18977  }
18978  else
18979  {
18980  Utilities->CallLogPop(369);
18981  return(NotAutoSigsRoute);
18982  }
18983  }
18984  }
18985  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18986  {
18987  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18988  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18989 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18990  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
18991  EntryLinkPos = PrefDirElement2.ELinkPos;
18992  ExitLinkPos = PrefDirElement2.XLinkPos;
18993  EntryLink = PrefDirElement2.Link[EntryLinkPos];
18994  ExitLink = PrefDirElement2.Link[ExitLinkPos];
18995  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
18996  {
18997  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
18998  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
18999  {
19000  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19001  }
19002  if(PrefDirElement2.AutoSignals)
19003  {
19004  Utilities->CallLogPop(370);
19005  return(AutoSigsRoute);
19006  }
19007  else
19008  {
19009  Utilities->CallLogPop(371);
19010  return(NotAutoSigsRoute);
19011  }
19012  }
19013  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
19014  {
19015  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19016  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
19017  {
19018  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19019  }
19020  if(PrefDirElement2.AutoSignals)
19021  {
19022  Utilities->CallLogPop(372);
19023  return(AutoSigsRoute);
19024  }
19025  else
19026  {
19027  Utilities->CallLogPop(373);
19028  return(NotAutoSigsRoute);
19029  }
19030  }
19031  ItPair.second--; // the second iterator points one past the last matching value
19032  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
19033  EntryLinkPos = PrefDirElement3.ELinkPos;
19034  ExitLinkPos = PrefDirElement3.XLinkPos;
19035  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19036  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19037  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
19038  {
19039  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19040  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
19041  {
19042  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19043  }
19044  if(PrefDirElement3.AutoSignals)
19045  {
19046  Utilities->CallLogPop(374);
19047  return(AutoSigsRoute);
19048  }
19049  else
19050  {
19051  Utilities->CallLogPop(375);
19052  return(NotAutoSigsRoute);
19053  }
19054  }
19055  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
19056  {
19057  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19058  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
19059  {
19060  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19061  }
19062  if(PrefDirElement3.AutoSignals)
19063  {
19064  Utilities->CallLogPop(376);
19065  return(AutoSigsRoute);
19066  }
19067  else
19068  {
19069  Utilities->CallLogPop(377);
19070  return(NotAutoSigsRoute);
19071  }
19072  }
19073  }
19074  Utilities->CallLogPop(378);
19075  return(NoRoute); // none found
19076 }
19077 
19078 // ---------------------------------------------------------------------------
19079 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
19080 /*
19081  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
19082  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
19083 */
19084 {
19085  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
19086  AnsiString(LinkPos));
19087  if(TrackVectorPosition == -1)
19088  {
19089  RouteNumber = -1;
19090  Utilities->CallLogPop(379);
19091  return(NoRoute); // allows for continuation & buffer entries & exits
19092  }
19093  THVPair Route2MultiMapKeyPair;
19094 
19095  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
19096  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
19097  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19098  TRoute2MultiMapIterator Route2MultiMapIterator;
19099 
19100  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19101  {
19102  RouteNumber = -1;
19103  Utilities->CallLogPop(380);
19104  return(NoRoute); // none found
19105  }
19106  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19107  {
19108  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19109 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19110  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
19111  Route2MultiMapIterator->second.second);
19112  EntryLinkPos = PrefDirElement1.ELinkPos;
19113  ExitLinkPos = PrefDirElement1.XLinkPos;
19114  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19115  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19116  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
19117  {
19118  RouteNumber = Route2MultiMapIterator->second.first;
19119  if(PrefDirElement1.AutoSignals)
19120  {
19121  Utilities->CallLogPop(381);
19122  return(AutoSigsRoute);
19123  }
19124  else
19125  {
19126  Utilities->CallLogPop(382);
19127  return(NotAutoSigsRoute);
19128  }
19129  }
19130  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
19131  {
19132  RouteNumber = Route2MultiMapIterator->second.first;
19133  if(PrefDirElement1.AutoSignals)
19134  {
19135  Utilities->CallLogPop(383);
19136  return(AutoSigsRoute);
19137  }
19138  else
19139  {
19140  Utilities->CallLogPop(384);
19141  return(NotAutoSigsRoute);
19142  }
19143  }
19144  }
19145  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19146  {
19147  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19148  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19149 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19150  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
19151  EntryLinkPos = PrefDirElement2.ELinkPos;
19152  ExitLinkPos = PrefDirElement2.XLinkPos;
19153  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19154  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19155  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
19156  {
19157  RouteNumber = ItPair.first->second.first;
19158  if(PrefDirElement2.AutoSignals)
19159  {
19160  Utilities->CallLogPop(385);
19161  return(AutoSigsRoute);
19162  }
19163  else
19164  {
19165  Utilities->CallLogPop(386);
19166  return(NotAutoSigsRoute);
19167  }
19168  }
19169  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
19170  {
19171  RouteNumber = ItPair.first->second.first;
19172  if(PrefDirElement2.AutoSignals)
19173  {
19174  Utilities->CallLogPop(387);
19175  return(AutoSigsRoute);
19176  }
19177  else
19178  {
19179  Utilities->CallLogPop(388);
19180  return(NotAutoSigsRoute);
19181  }
19182  }
19183  ItPair.second--; // the second iterator points one past the last matching value
19184  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
19185  EntryLinkPos = PrefDirElement3.ELinkPos;
19186  ExitLinkPos = PrefDirElement3.XLinkPos;
19187  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19188  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19189  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
19190  {
19191  RouteNumber = ItPair.second->second.first;
19192  if(PrefDirElement3.AutoSignals)
19193  {
19194  Utilities->CallLogPop(389);
19195  return(AutoSigsRoute);
19196  }
19197  else
19198  {
19199  Utilities->CallLogPop(390);
19200  return(NotAutoSigsRoute);
19201  }
19202  }
19203  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
19204  {
19205  RouteNumber = ItPair.second->second.first;
19206  if(PrefDirElement3.AutoSignals)
19207  {
19208  Utilities->CallLogPop(391);
19209  return(AutoSigsRoute);
19210  }
19211  else
19212  {
19213  Utilities->CallLogPop(392);
19214  return(NotAutoSigsRoute);
19215  }
19216  }
19217  }
19218  RouteNumber = -1;
19219  Utilities->CallLogPop(393);
19220  return(NoRoute); // none found
19221 }
19222 
19223 // ---------------------------------------------------------------------------
19224 
19225 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
19226 /*
19227  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
19228  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
19229  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
19230  and Route2MultiMap.
19231 */
19232 {
19233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
19234  TOneRoute EmptyRoute;
19235 
19236  EmptyRoute.RouteID = NextRouteID;
19237  NextRouteID++;
19238 
19239  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19240  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19241  {
19242  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
19243  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
19244  }
19245  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
19246  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
19247 
19248  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
19249  Utilities->CallLogPop(394);
19250 }
19251 
19252 // ---------------------------------------------------------------------------
19253 
19255 /*
19256  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
19257  that is already in Route is used.
19258 */
19259 {
19260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
19261  TOneRoute EmptyRoute;
19262 
19263  EmptyRoute.RouteID = Route->RouteID;
19264 
19265  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19266  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19267  {
19268  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
19269  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
19270  }
19271  Utilities->CallLogPop(1579);
19272 }
19273 
19274 // ---------------------------------------------------------------------------
19275 
19276 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
19277 /*
19278  When attaching a new route section to an existing route, it is sometimes necessary to erase the
19279  original route and create a new composite route. This function Erases all elements in the route
19280  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
19281  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
19282  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
19283  that are greater than the route number that is removed. The LockedRouteVector as also searched
19284  and if any relate to the route that has been cleared they are erased too, but the fact that one
19285  has been found is recorded so that it can be re-established later.
19286 */
19287 {
19288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
19289  THVPair Route2MultiMapKeyPair;
19290  TRoute2MultiMapEntry Route2MultiMapEntry;
19291  TRoute2MultiMapIterator Route2MultiMapIterator;
19292 
19293 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
19294 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
19295 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
19296 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
19297 // If so the locked route is removed from the locked vector and is lost.
19298  LockedRouteRearTrackVectorPosition = 0;
19299  LockedRouteLastTrackVectorPosition = 0;
19300  LockedRouteLastXLinkPos = 0;
19301  LockedRouteLockStartTime = TDateTime(0);
19302  if(!LockedRouteVector.empty())
19303  {
19304  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19305  {
19306  if(LRVIT->RouteNumber == RouteNumber)
19307  {
19308  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
19309  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
19310  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
19311  LockedRouteLockStartTime = LRVIT->LockStartTime;
19312  LockedRouteFoundDuringRouteBuilding = true;
19313  LockedRouteVector.erase(LRVIT);
19314  }
19315  }
19316  }
19317  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
19318  {
19319  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
19320  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
19321  }
19322  Utilities->CallLogPop(395);
19323 }
19324 
19325 // ---------------------------------------------------------------------------
19326 
19328  TRoute2MultiMapIterator &Route2MultiMapIterator)
19329 /*
19330  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
19331  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
19332  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
19333  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
19334  are given for failure.
19335 */
19336 {
19337  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19338  AnsiString(VLoc) + "," + AnsiString(ELink));
19339  TRouteElementPair ReturnPair;
19340 
19341  ReturnPair.first = -1;
19342  ReturnPair.second = 0;
19343  THVPair Route2MultiMapKeyPair;
19344 
19345  Route2MultiMapKeyPair.first = HLoc;
19346  Route2MultiMapKeyPair.second = VLoc;
19347  TRoute2MultiMapEntry Route2MultiMapEntry;
19348 
19349  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
19350  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19351 
19352  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19353  Route2MultiMapIterator = ItPair.first;
19354 
19355  if(ItPair.first == ItPair.second)
19356  {
19357  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
19358  }
19359  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
19360  {
19361  ReturnPair.first = ItPair.first->second.first;
19362  ReturnPair.second = ItPair.first->second.second;
19363  Route2MultiMapIterator = ItPair.first;
19364  Utilities->CallLogPop(396);
19365  return(ReturnPair);
19366  }
19367  ItPair.first++;
19368  if(ItPair.first == ItPair.second)
19369  {
19370  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
19371  }
19372  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
19373  {
19374  ReturnPair.first = ItPair.first->second.first;
19375  ReturnPair.second = ItPair.first->second.second;
19376  Route2MultiMapIterator = ItPair.first;
19377  Utilities->CallLogPop(397);
19378  return(ReturnPair);
19379  }
19380  Utilities->CallLogPop(398);
19381  return(ReturnPair);
19382 }
19383 
19384 // ---------------------------------------------------------------------------
19385 
19386 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
19387 /*
19388  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
19389  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
19390  RouteNumber (route position in AllRoutes vector is returned as a reference.
19391  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
19392  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
19393 */
19394 {
19395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
19396  AnsiString(VLoc) + "," + AnsiString(ELink));
19397  THVPair Route2MultiMapKeyPair;
19398 
19399  Route2MultiMapKeyPair.first = HLoc;
19400  Route2MultiMapKeyPair.second = VLoc;
19401  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19402 
19403  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19404 
19405  if(ItPair.first == ItPair.second)
19406  {
19407  RouteNumber = -1;
19408  Utilities->CallLogPop(2032);
19409  return(false);
19410  }
19411  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
19412  {
19413  RouteNumber = ItPair.first->second.first;
19414  Utilities->CallLogPop(2033);
19415  return(true);
19416  }
19417  ItPair.first++;
19418 
19419  if(ItPair.first == ItPair.second)
19420  {
19421  RouteNumber = -1;
19422  Utilities->CallLogPop(2034);
19423  return(false);
19424  }
19425  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
19426  {
19427  RouteNumber = ItPair.first->second.first;
19428  Utilities->CallLogPop(2035);
19429  return(true);
19430  }
19431  RouteNumber = -1;
19432  Utilities->CallLogPop(2036);
19433  return(false);
19434 }
19435 
19436 // ---------------------------------------------------------------------------
19437 
19438 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
19439 /*
19440  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
19441  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
19442  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
19443  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
19444  Called by TAllRoutes::AddRouteElement.
19445 */
19446 {
19447  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19448  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
19449  THVPair Route2MultiMapKeyPair;
19450 
19451  Route2MultiMapKeyPair.first = HLoc;
19452  Route2MultiMapKeyPair.second = VLoc;
19453  TRoute2MultiMapEntry Route2MultiMapEntry;
19454 
19455  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
19456  TRouteElementPair RouteElementPair;
19457 
19458  RouteElementPair.first = RouteNumber;
19459  RouteElementPair.second = RouteElementNumber;
19460  Route2MultiMapEntry.second = RouteElementPair;
19461 
19462  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
19463  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
19464  {
19465  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
19466  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
19467  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
19468  {
19469  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
19470  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
19471  {
19472  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
19473  }
19474  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
19475  }
19476  else
19477  // same ELink so have an error
19478  {
19479  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
19480  }
19481  }
19482  else
19483  {
19484  Route2MultiMap.insert(Route2MultiMapEntry);
19485  }
19486 // element at H&V not found in map so insert it
19487  Utilities->CallLogPop(399);
19488 }
19489 
19490 // ---------------------------------------------------------------------------
19491 
19493 /*
19494  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
19495  and the second in the reference SecondPair. If there's only one then it's the function return
19496 */
19497 {
19498  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19499  AnsiString(VLoc));
19501 
19502  TempPair.first = -1;
19503  TempPair.second = 0;
19504  SecondPair = TempPair;
19505  TRoute2MultiMapIterator Route2MultiMapIterator;
19506  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
19507  THVPair Route2MultiMapKeyPair;
19508 
19509  Route2MultiMapKeyPair.first = HLoc;
19510  Route2MultiMapKeyPair.second = VLoc;
19511  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19512  {
19513  Utilities->CallLogPop(400);
19514  return(TempPair);
19515  }
19516  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19517  {
19518  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19519  Utilities->CallLogPop(401);
19520  return(Route2MultiMapIterator->second);
19521  }
19522  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19523  {
19524  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19525  TempPair = ItRange.first->second;
19526  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
19527  Utilities->CallLogPop(402);
19528  return(TempPair);
19529  }
19530  Utilities->CallLogPop(403);
19531  return(TempPair);
19532 }
19533 
19534 // ---------------------------------------------------------------------------
19535 
19536 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
19537 /*
19538  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
19539  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
19540 */
19541 {
19542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
19543  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
19544  {
19545  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
19546  {
19547  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
19548  TAllRoutes::TRouteElementPair SecondPair;
19549  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
19550  if(RouteElementPair.first == -1)
19551  // failed to find element in multimap
19552  {
19553  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
19554  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
19555  }
19556  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
19557  // neither pair has expected route number
19558  {
19559  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19560  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
19561  (AnsiString)Caller);
19562  }
19563  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
19564  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
19565  {
19566  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19567  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
19568  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
19569  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
19570  }
19571  }
19572  }
19573  unsigned int SizeVal = 0;
19574 
19575 // check map and sum of route sizes match
19576  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19577  {
19578  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
19579  }
19580  if(SizeVal != Route2MultiMap.size())
19581  {
19582  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
19583  (AnsiString)Caller);
19584  }
19585  Utilities->CallLogPop(404);
19586  return;
19587 }
19588 
19589 // ---------------------------------------------------------------------------
19590 
19591 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
19592 /*
19593  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
19594  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
19595  exceed that for the erased route. Where this is so the RouteNumber is decremented.
19596 */
19597 {
19598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
19599  if(!Route2MultiMap.empty())
19600  {
19601  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19602  {
19603  if(Route2MultiMapIterator->second.first > RouteNumber)
19604  {
19605  Route2MultiMapIterator->second.first--;
19606  }
19607  }
19608  }
19609  Utilities->CallLogPop(405);
19610 }
19611 
19612 // ---------------------------------------------------------------------------
19613 
19614 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
19615 /*
19616  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
19617  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
19618  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
19619 */
19620 {
19621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
19622  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
19623  if(!Route2MultiMap.empty())
19624  {
19625  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19626  {
19627  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
19628  {
19629  Route2MultiMapIterator->second.second--;
19630  }
19631  }
19632  }
19633  Utilities->CallLogPop(406);
19634 }
19635 
19636 // ---------------------------------------------------------------------------
19637 
19638 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
19639 /*
19640  Erases the route element from Route2MultiMap and from the PrefDirVector.
19641  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
19642  decremented if they are greater than the element number removed, and if the entire route is removed
19643  then the route numbers are also decremented in the map for route numbers that are greater than the route
19644  number that is removed.
19645 */
19646 {
19647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19648  AnsiString(ELink));
19649  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
19650  TRoute2MultiMapIterator Route2MultiMapIterator;
19651 
19652  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
19653  if(RequiredRoutePair.first == -1)
19654  {
19655  throw Exception("Failed to find route element in RemoveRouteElement");
19656  }
19657  Route2MultiMap.erase(Route2MultiMapIterator);
19658  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
19659 
19660 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
19661  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
19662 
19663  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
19664  {
19665  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
19666  }
19667 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
19668 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
19669 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
19670 // to check if a route element is present, and the element has already been removed from the map - see above.
19671 
19672 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
19673 /*
19674  int LockedVectorNumber = -1;
19675  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
19676  {
19677  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
19678  }
19679 */
19680 
19681 // erase element from route
19682  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
19683 // CheckMapAndRoutes();//test - drop - tested below
19684 
19685 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
19686 // be so as continuation exit is at the end of the route, and truncation is from the end
19688  {
19690  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19691  AutoSigVectorIT--)
19692  {
19693  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
19694  {
19695  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
19696  }
19697  }
19698  }
19699 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
19700 // and adjust all the corresponding route numbers
19701  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
19702  {
19703  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
19704  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
19705  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
19706 
19707 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
19708  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
19709  it is erased then - see TInterface::ApproachLocking
19710 
19711  if(LockedVectorNumber > -1)
19712  {
19713  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
19714  }
19715 */
19716  // decrement route numbers in the locked route vector whether or not this route is a locked route
19717  if(!LockedRouteVector.empty())
19718  {
19719  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19720  {
19721  if(LRVIT->RouteNumber > RequiredRoutePair.first)
19722  {
19723  LRVIT->RouteNumber--;
19724  }
19725  }
19726  }
19728  {
19730  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19731  AutoSigVectorIT--)
19732  {
19733  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
19734  {
19735  AutoSigVectorIT->RouteNumber--;
19736  }
19737  }
19738  }
19739  }
19740  CheckMapAndRoutes(7); // test
19741  Utilities->CallLogPop(407);
19742 }
19743 
19744 // ---------------------------------------------------------------------------
19745 
19746 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
19747 /*
19748  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
19749  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
19750  since that catches all route elements wherever created
19751 */
19752 {
19753  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19754  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
19755  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
19756  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
19757  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
19758 } //number is one less than this
19759 
19760 // ---------------------------------------------------------------------------
19761 
19762 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
19763 /*
19764  Enter with signal at TrackVectorElement already set to red by the passing train.
19765  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
19766  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
19767  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
19768  case the function sets no further signals.
19769 */
19770 {
19771  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
19772  "," + AnsiString(XLinkPos));
19773  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
19774  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
19775 
19776  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
19777  if(RouteElementPair.first == -1)
19778  {
19779  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
19780  }
19781  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
19782 
19783  RequiredPair = RouteElementPair;
19784  if(RouteElement.XLinkPos != XLinkPos)
19785  {
19786  if(SecondPair.first != -1)
19787  {
19788  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
19789  RequiredPair = SecondPair;
19790  if(RouteElement.XLinkPos != XLinkPos)
19791  {
19792  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
19793  }
19794  }
19795  else
19796  {
19797  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
19798  }
19799  }
19800 // new function
19801  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
19802  Utilities->CallLogPop(409);
19803 }
19804 
19805 // ---------------------------------------------------------------------------
19806 
19807 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
19808 /*
19809  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
19810  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
19811  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
19812  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
19813  to 2 for successive calls.
19814  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
19815  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
19816  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
19817  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
19818 */
19819 {
19820  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
19821  AnsiString(AccessNumber));
19822  TPrefDirElement RouteElement;
19823  int Attribute = AccessNumber + 1;
19824 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
19825  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
19826 
19827  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
19828  {
19829  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
19830  }
19831  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
19832  {
19833  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
19834  }
19835  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
19836  x).XLinkPos] != End)
19837  {
19838  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
19839  }
19840 // new function
19841  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
19842  Utilities->CallLogPop(410);
19843 }
19844 
19845 // ---------------------------------------------------------------------------
19846 
19847 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
19848 /*
19849  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
19850  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
19851  or (b) in a linked rear route, in which case the function sets no further signals.
19852 
19853  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
19854  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
19855  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
19856  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
19857  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
19858  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
19859  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
19860  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
19861  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
19862  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
19863  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
19864  found behind the train.
19865 
19866  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
19867  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
19868  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
19869  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
19870  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
19871  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
19872  a route.
19873 
19874  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
19875  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
19876  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
19877  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
19878  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
19879  reference. If no train is found before the beginning of the route is reached the function returns true
19880 
19881 */
19882 {
19883  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
19884  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
19885  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
19886  int RearwardLinkedRouteNumber;
19887 
19888  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
19889  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
19890  // signal value in the route for use in further linked routes
19891  {
19892  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
19893  {
19894  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
19895  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
19896  {
19897  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
19898  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
19899  {
19900  break;
19901  }
19902  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
19903  // flash LCs on those routes
19904  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
19905  }
19906  }
19907  }
19908  else
19909  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
19910  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
19911  {
19912  int TrainID, TrainPosition, BehindTrainPosition;
19913  bool FoundTrain = false, BehindTrain = false;
19914  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
19915  {
19916  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
19917  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
19918  TrainID = TrackElement.TrainIDOnElement;
19919  if(TrackElement.TrackType == Bridge)
19920  {
19921  if(PrefDirElement.XLinkPos < 2)
19922  {
19923  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19924  }
19925  else
19926  {
19927  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19928  }
19929  }
19930  if(TrainID == -1)
19931  {
19932  continue;
19933  }
19934  else
19935  {
19936  FoundTrain = true;
19937  TrainPosition = x;
19938  break;
19939  }
19940  }
19941  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
19942  {
19943  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
19944  {
19945  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
19946  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
19947  // need the element behind the rearmost train.
19948  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
19949  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
19950  TrainID = TrackElement.TrainIDOnElement;
19951  if(TrackElement.TrackType == Bridge)
19952  {
19953  if(PrefDirElement.XLinkPos < 2)
19954  {
19955  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19956  }
19957  else
19958  {
19959  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19960  }
19961  }
19962  if(TrainID != -1)
19963  {
19964  continue; // still on train
19965  }
19966  else
19967  {
19968  BehindTrain = true;
19969  BehindTrainPosition = x;
19970  break;
19971  }
19972  }
19973  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
19974  // so on for as many trains as there are on the single route
19975  {
19976  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
19977  // first signal behind train to be red
19978  }
19979  }
19980  }
19981  Utilities->CallLogPop(411);
19982 }
19983 
19984 // ---------------------------------------------------------------------------
19985 
19986 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
19987 {
19988 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
19989 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
19990 rearmost linked route) - this because train cancels route elements that it touches)
19991 */
19992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
19993  AnsiString(LookBackwardsFromHere));
19994  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
19995  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
19996  TPrefDirElement PrefDirElement, FirstElement;
19997  TTrackElement TrackElement;
19998  bool ExamineRoute = true;
19999 
20000  while(ExamineRoute)
20001  {
20002  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
20003  {
20004  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
20005  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
20006  TrainID = TrackElement.TrainIDOnElement;
20007  if(TrackElement.TrackType == Bridge)
20008  {
20009  if(PrefDirElement.XLinkPos < 2)
20010  {
20011  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20012  }
20013  else
20014  {
20015  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20016  }
20017  }
20018  if(TrainID > -1)
20019  {
20020  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
20021  {
20022  //any trains further back in route will be protected by the red signal behind the stopped train
20023  Utilities->CallLogPop(412);
20024  return(false);
20025  }
20026  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
20027  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
20028  //other way & can cancel the route
20029  {
20030  Utilities->CallLogPop(2203);
20031  return(false);
20032  }
20033  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
20034  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
20035  }
20036  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
20037  {
20038  if(TrackElement.Attribute == 0)
20039  {
20040  Utilities->CallLogPop(413);
20041  return(false); // OK, red signal in front of a train
20042  }
20043  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
20044  {
20045  SignalCount++;
20046  }
20047  if(SignalCount >= 3)
20048  {
20049  Utilities->CallLogPop(414);
20050  return(false);
20051  }
20052  }
20053  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
20054  // ElinkPos because working back along PrefDir to beginning
20055  {
20056  Utilities->CallLogPop(415);
20057  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
20058  }
20059  }
20060  //now look at linked rearwards routes
20061  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
20062  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
20063  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20064  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
20065  {
20066  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
20067  ExamineRoute = true;
20068  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
20069  }
20070  else
20071  {
20072  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
20073  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
20074  TrainID = PriorTrackElement.TrainIDOnElement;
20075  if(PriorTrackElement.TrackType == Bridge)
20076  {
20077  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
20078  {
20079  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20080  }
20081  else
20082  {
20083  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20084  }
20085  }
20086  if(TrainID > -1)
20087  {
20088  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
20089  {
20090  Utilities->CallLogPop(748);
20091  return(false);
20092  }
20093  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
20094  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
20095  //other way & can cancel the route
20096  {
20097  Utilities->CallLogPop(2204);
20098  return(false);
20099  }
20100  Utilities->CallLogPop(1962);
20101  return(true); //otherwise need to lock the route
20102  }
20103  ExamineRoute = false;
20104  }
20105  }
20106 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
20107 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
20108  Utilities->CallLogPop(416);
20109  return(false);
20110 }
20111 
20112 // ---------------------------------------------------------------------------
20113 
20114 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
20115  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
20116 {
20117  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
20118  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
20119  TPrefDirElement InternalPrefDirElement; // blank element
20120 
20121  PrefDirElement = InternalPrefDirElement;
20122  if(LockedRouteVector.empty())
20123  {
20124  Utilities->CallLogPop(417);
20125  return(false);
20126  }
20127 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
20128 // even if some elements have been removed from the front by a train
20129  bool InLockedRoute = false;
20130 
20131  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20132  {
20133  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
20134  {
20135  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
20136  // doesn't arise)
20137  InLockedRoute = true;
20138  break;
20139  }
20140  }
20141  if(!InLockedRoute)
20142  {
20143  Utilities->CallLogPop(418);
20144  return(false);
20145  }
20146  int RouteNumber, VectorCount = 0;
20147  TRouteType RouteType;
20148 
20149  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20150  {
20151  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
20152  if(RouteType == NoRoute)
20153  {
20154  continue;
20155  }
20156 /* can't use this test with front truncation
20157  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
20158  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
20159  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
20160  {
20161  throw Exception
20162  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
20163  }
20164 */
20165  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
20166  {
20167  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
20168  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
20169  {
20170  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20171  {
20172  PrefDirElement = InternalPrefDirElement;
20173  LockedVectorNumber = VectorCount;
20174  Utilities->CallLogPop(419);
20175  return(true);
20176  }
20177  }
20178  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
20179  {
20180  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20181  {
20182  PrefDirElement = InternalPrefDirElement;
20183  LockedVectorNumber = VectorCount;
20184  Utilities->CallLogPop(420);
20185  return(true);
20186  }
20187  else
20188  {
20189  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
20190  }
20191  }
20192  }
20193  VectorCount++;
20194  }
20195  Utilities->CallLogPop(421);
20196  return(false);
20197 }
20198 
20199 // ---------------------------------------------------------------------------
20200 
20202 {
20203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
20204  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20205  {
20206  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
20207  {
20208  Utilities->CallLogPop(963);
20209  return(x);
20210  }
20211  }
20212  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
20213 }
20214 
20215 // ---------------------------------------------------------------------------
20216 
20218 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
20219 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
20220 {
20221  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20222  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20223  {
20224  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
20225  {
20226  Utilities->CallLogPop(2039);
20227  return(true);
20228  }
20229  }
20230  Utilities->CallLogPop(2040);
20231  return(false);
20232 }
20233 
20234 // ---------------------------------------------------------------------------
20235 
20237 {
20238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20239  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20240  {
20241  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
20242  {
20243  Utilities->CallLogPop(964);
20244  return(GetFixedRouteAt(159, x));
20245  }
20246  }
20247  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20248 }
20249 
20250 // ---------------------------------------------------------------------------
20251 
20253 {
20254  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
20255  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20256  {
20257  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
20258  {
20259  Utilities->CallLogPop(965);
20260  return(GetModifiableRouteAt(15, x));
20261  }
20262  }
20263  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20264 }
20265 
20266 // ---------------------------------------------------------------------------
20267 
20268 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
20269 {
20270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
20271  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
20272  Utilities->SaveFileInt(OutFile, NextRouteID);
20273  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20274  {
20275  TOneRoute OneRoute = GetFixedRouteAt(165, x);
20276  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
20277  OneRoute.SavePrefDirVector(6, OutFile);
20278  }
20279  Utilities->CallLogPop(1442);
20280 }
20281 
20282 // ---------------------------------------------------------------------------
20283 
20284 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
20285 {
20286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
20287  int NumberOfRoutes;
20288 
20289  NumberOfRoutes = Utilities->LoadFileInt(InFile);
20290  NextRouteID = Utilities->LoadFileInt(InFile);
20291  for(int x = 0; x < NumberOfRoutes; x++)
20292  {
20293  TOneRoute OneRoute; // empty route
20294  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
20295  OneRoute.LoadPrefDir(2, InFile);
20297  {
20298  StoreOneRouteAfterSessionLoad(0, &OneRoute);
20299  }
20300  else
20301  {
20302  Utilities->CallLogPop(1443);
20303  return(false);
20304  }
20305  }
20306  Utilities->CallLogPop(1444);
20307  return(true);
20308 }
20309 
20310 // ---------------------------------------------------------------------------
20311 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
20312 {
20313  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
20314  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
20315 
20316  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
20317  {
20318  Utilities->CallLogPop(1445);
20319  return(false);
20320  }
20321  int NextID = Utilities->LoadFileInt(InFile);
20322 
20323  if((NextID < 0) || (NextID > 1000000))
20324  {
20325  Utilities->CallLogPop(1446);
20326  return(false);
20327  }
20328  for(int x = 0; x < NumberOfRoutes; x++)
20329  {
20330  int RouteID = Utilities->LoadFileInt(InFile);
20331  if((RouteID < 0) || (RouteID > 20000))
20332  {
20333  Utilities->CallLogPop(1447);
20334  return(false);
20335  }
20336  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
20337  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
20338  {
20339  Utilities->CallLogPop(1448);
20340  return(false);
20341  }
20342  }
20343  Utilities->CallLogPop(1449);
20344  return(true);
20345 }
20346 
20347 // ---------------------------------------------------------------------------
20348 
20349 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
20350 {
20351  // return true for a loop
20352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
20353  AnsiString(StartPosition));
20354  if(EndPosition == StartPosition)
20355  {
20356  Utilities->CallLogPop(1839);
20357  return(true); // shouldn't happen but treat as a loop if does
20358  }
20359 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
20360  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
20361  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
20362 
20363  while(TrackIsInARoute(15, TVPos, LkPos))
20364  {
20365  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
20366  int NewLkPos = -1;
20367  if(NewTVPos > -1)
20368  {
20369  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
20370  if(NewLkPos == -1)
20371  {
20372  Utilities->CallLogPop(1840);
20373  return(true); // shouldn't arise but treat as loop if does
20374  }
20375  }
20376  else // reached a buffer or continuation
20377  {
20378  Utilities->CallLogPop(1841);
20379  return(false);
20380  }
20381 //Error found by Xeon notified by email 13/10/20.
20382 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
20383 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
20384 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
20385 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
20386 //New check added for v2.6.0
20387 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
20388 //as possible in case there are other unforeseen effects.
20389  int RouteNumber; //dummy, not used
20390  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
20391  {
20392  Utilities->CallLogPop(2241);
20393  return(false);
20394  }
20395  //now make the connected element the current element, read across the TV number and determine the exit link
20396  TVPos = NewTVPos;
20397  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
20398  {
20399  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
20400  {
20401  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
20402  {
20403  LkPos = 1;
20404  }
20405  else
20406  {
20407  LkPos = 3;
20408  }
20409  }
20410  else
20411  {
20412  LkPos = 0;
20413  }
20414  }
20415  else
20416  {
20417  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
20418  }
20419  if(TVPos == StartPosition)
20420  {
20421  Utilities->CallLogPop(1842);
20422  return(true); // it is a loop
20423  }
20424  }
20425  Utilities->CallLogPop(1843);
20426  return(false); // reached end of route so not a loop
20427 }
20428 
20429 // ---------------------------------------------------------------------------
20430 
20431 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20432 /*
20433  Track geometry allows diagonals to cross without occupying the same track element, so when
20434  route plotting it is necessary to check if there is an existing route or a train on such a crossing
20435  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
20436  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20437  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20438  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20439  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20440  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20441  Each of these is examined in turn for each route element in the relevant position.
20442 
20443  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
20444  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
20445  that returns false in all cases (including elements & links not present) except train present.
20446 */
20447 {
20448  int TrainID; // not used in this function
20449 
20450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
20451  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
20452  TPrefDirElement TempPrefDirElement;
20453  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20454 
20455  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
20456  if(FirstPair.first > -1)
20457  {
20458  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
20459  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20460  {
20461  Utilities->CallLogPop(310);
20462  return(true);
20463  }
20464  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20465  {
20466  Utilities->CallLogPop(311);
20467  return(true);
20468  }
20469  }
20470  if(SecondPair.first > -1)
20471  {
20472  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
20473  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20474  {
20475  Utilities->CallLogPop(312);
20476  return(true);
20477  }
20478  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20479  {
20480  Utilities->CallLogPop(313);
20481  return(true);
20482  }
20483  }
20484  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
20485  9, TrainID)))
20486  {
20487  Utilities->CallLogPop(1997);
20488  return(true);
20489  }
20490  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
20491  if(FirstPair.first > -1)
20492  {
20493  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
20494  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20495  {
20496  Utilities->CallLogPop(314);
20497  return(true);
20498  }
20499  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20500  {
20501  Utilities->CallLogPop(315);
20502  return(true);
20503  }
20504  }
20505  if(SecondPair.first > -1)
20506  {
20507  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
20508  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20509  {
20510  Utilities->CallLogPop(316);
20511  return(true);
20512  }
20513  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20514  {
20515  Utilities->CallLogPop(317);
20516  return(true);
20517  }
20518  }
20519  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
20520  9, TrainID)))
20521  {
20522  Utilities->CallLogPop(1998);
20523  return(true);
20524  }
20525  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
20526  if(FirstPair.first > -1)
20527  {
20528  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
20529  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20530  {
20531  Utilities->CallLogPop(318);
20532  return(true);
20533  }
20534  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20535  {
20536  Utilities->CallLogPop(319);
20537  return(true);
20538  }
20539  }
20540  if(SecondPair.first > -1)
20541  {
20542  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
20543  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20544  {
20545  Utilities->CallLogPop(320);
20546  return(true);
20547  }
20548  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20549  {
20550  Utilities->CallLogPop(321);
20551  return(true);
20552  }
20553  }
20554  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
20555  7, TrainID)))
20556  {
20557  Utilities->CallLogPop(1999);
20558  return(true);
20559  }
20560  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
20561  if(FirstPair.first > -1)
20562  {
20563  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
20564  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20565  {
20566  Utilities->CallLogPop(322);
20567  return(true);
20568  }
20569  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20570  {
20571  Utilities->CallLogPop(323);
20572  return(true);
20573  }
20574  }
20575  if(SecondPair.first > -1)
20576  {
20577  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
20578  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20579  {
20580  Utilities->CallLogPop(324);
20581  return(true);
20582  }
20583  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20584  {
20585  Utilities->CallLogPop(325);
20586  return(true);
20587  }
20588  }
20589  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
20590  3, TrainID)))
20591  {
20592  Utilities->CallLogPop(2000);
20593  return(true);
20594  }
20595  Utilities->CallLogPop(326);
20596  return(false);
20597 }
20598 
20599 // ---------------------------------------------------------------------------
20600 
20601 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20602 /*
20603  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
20604  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20605  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20606  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20607  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20608  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20609  Each of these is examined in turn for each route element in the relevant position.
20610 */
20611 {
20612  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20613  "," + AnsiString(DiagonalLinkNumber));
20614  TPrefDirElement TempPrefDirElement;
20615  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20616 
20617  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
20618  if(FirstPair.first > -1)
20619  {
20620  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
20621  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20622  {
20623  Utilities->CallLogPop(2010);
20624  return(true);
20625  }
20626  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20627  {
20628  Utilities->CallLogPop(2011);
20629  return(true);
20630  }
20631  }
20632  if(SecondPair.first > -1)
20633  {
20634  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
20635  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20636  {
20637  Utilities->CallLogPop(2012);
20638  return(true);
20639  }
20640  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20641  {
20642  Utilities->CallLogPop(2013);
20643  return(true);
20644  }
20645  }
20646  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
20647  if(FirstPair.first > -1)
20648  {
20649  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
20650  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20651  {
20652  Utilities->CallLogPop(2014);
20653  return(true);
20654  }
20655  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20656  {
20657  Utilities->CallLogPop(2015);
20658  return(true);
20659  }
20660  }
20661  if(SecondPair.first > -1)
20662  {
20663  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
20664  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20665  {
20666  Utilities->CallLogPop(2016);
20667  return(true);
20668  }
20669  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20670  {
20671  Utilities->CallLogPop(2017);
20672  return(true);
20673  }
20674  }
20675  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
20676  if(FirstPair.first > -1)
20677  {
20678  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
20679  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20680  {
20681  Utilities->CallLogPop(2018);
20682  return(true);
20683  }
20684  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20685  {
20686  Utilities->CallLogPop(2019);
20687  return(true);
20688  }
20689  }
20690  if(SecondPair.first > -1)
20691  {
20692  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
20693  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20694  {
20695  Utilities->CallLogPop(2020);
20696  return(true);
20697  }
20698  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20699  {
20700  Utilities->CallLogPop(2021);
20701  return(true);
20702  }
20703  }
20704  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
20705  if(FirstPair.first > -1)
20706  {
20707  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
20708  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20709  {
20710  Utilities->CallLogPop(2022);
20711  return(true);
20712  }
20713  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20714  {
20715  Utilities->CallLogPop(2023);
20716  return(true);
20717  }
20718  }
20719  if(SecondPair.first > -1)
20720  {
20721  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
20722  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20723  {
20724  Utilities->CallLogPop(2024);
20725  return(true);
20726  }
20727  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20728  {
20729  Utilities->CallLogPop(2025);
20730  return(true);
20731  }
20732  }
20733  Utilities->CallLogPop(2026);
20734  return(false);
20735 }
20736 
20737 // ---------------------------------------------------------------------------
20738 
20739 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9411
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:18842
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1321
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11701
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11674
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:438
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4775
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:572
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5647
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13219
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1735
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:813
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:19438
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10156
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:19847
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1375
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:805
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13743
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:823
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:436
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13259
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3843
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:803
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:286
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7402
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:18804
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:97
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1715
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:729
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5799
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7303
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5826
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1531
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:592
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1676
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1975
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10490
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:622
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:17582
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:20601
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:438
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1706
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:70
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:613
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2871
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:557
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5979
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8330
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1541
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:651
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:19276
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:584
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12998
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7788
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10694
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9534
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14392
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:16910
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1141
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:19638
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:761
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1656
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12802
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4530
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3709
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1553
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8145
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:444
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4690
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1335
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6586
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10979
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3585
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1334
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:20114
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2904
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7774
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:227
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:20311
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:580
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9701
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1714
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1551
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1643
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:209
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:736
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:442
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:819
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3309
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16103
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8597
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13064
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:807
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:77
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2920
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:731
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1042
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:19386
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1402
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13315
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3906
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1781
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5939
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:307
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:744
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:381
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14263
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11715
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:576
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:632
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7803
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:89
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:19746
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7549
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:613
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:574
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10595
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1555
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1519
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:709
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:586
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:809
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1411
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6210
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1557
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:624
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8951
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:569
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10704
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1055
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:304
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:747
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:815
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3880
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:874
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:231
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9666
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1036
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:18792
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:508
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1680
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7817
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:674
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6995
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:649
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:229
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8990
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:18777
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:592
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:827
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14032
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13769
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:927
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4615
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1925
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:436
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:787
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11182
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:19591
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4869
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1944
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:797
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:763
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:564
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1739
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:659
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11427
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:20217
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:592
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1053
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2888
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1563
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15267
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7430
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8787
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7509
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5850
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:696
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:322
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:687
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:18308
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1337
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:874
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13403
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12538
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1681
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1733
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:793
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13031
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:714
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:18434
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3686
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13722
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11470
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10845
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1827
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:939
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:583
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6033
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12851
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:827
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:628
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2943
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11727
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12046
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:433
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10739
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:119
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5898
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1861
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13970
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6110
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:893
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5690
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17851
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6567
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:95
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1366
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9462
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:713
TTrack::Up
@ Up
Definition: TrackUnit.h:613
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:829
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:587
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10718
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1513
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8754
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1674
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:759
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:205
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:18510
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1663
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6453
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:831
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8700
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7458
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10129
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:574
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:592
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:795
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19079
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1595
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12901
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11366
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4699
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:572
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10690
TGraphicElement::Width
int Width
Definition: TrackUnit.h:440
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:19986
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:20201
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:18905
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:801
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:804
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14801
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:661
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4188
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2406
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:694
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9602
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:12669
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:793
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:966
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5874
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:20284
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1555
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1544
TAllRoutes::RouteBackTruncateFlag
bool RouteBackTruncateFlag
used to flag the fact that a route is being truncated from the back in order to change the behaviour ...
Definition: TrackUnit.h:1720
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7156
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:765
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1066
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1068
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7989
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:18602
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:662
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7531
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5495
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:827
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13792
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:620
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11278
Parapet
@ Parapet
Definition: TrackUnit.h:67
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:18751
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:115
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:274
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9271
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:18575
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:827
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:19614
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:799
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1071
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:739
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:16503
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:207
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11498
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:12596
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1315
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:18538
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:550
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1374
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:874
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1405
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:19762
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1713
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1650
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8299
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:205
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:19254
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:213
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3023
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9959
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6347
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2158
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:589
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:807
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2624
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:203
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1648
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7953
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12384
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13162
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:588
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1519
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10627
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8663
IDInt
Definition: TrackUnit.h:499
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2601
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:20252
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4503
TDisplay
Definition: DisplayUnit.h:49
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10377
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5240
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:876
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:442
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:20349
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1155
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9385
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:572
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7900
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1316
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13472
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:783
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:211
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14598
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1718
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7868
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:634
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:909
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1530
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1654
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1664
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4791
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9211
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:715
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15909
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1344
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:436
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13898
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1322
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13673
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:19327
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:10060
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11349
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4210
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:18487
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9444
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:17674
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1897
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:17430
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1062
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7747
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3786
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6130
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:13570
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:592
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9491
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12427
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:578
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:715
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:436
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:592
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1051
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:793
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3403
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:440
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1547
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:682
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:741
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1712
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:268
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:20431
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13367
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1040
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1521
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1044
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:789
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:903
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4758
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:19225
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1745
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8801
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:698
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:811
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:11136
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:709
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1376
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:18629
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:716
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:20268
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:582
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1907
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4741
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3763
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9723
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17243
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:11656
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12245
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8727
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:11628
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1049
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:19536
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:19492
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7229
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11007
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:735
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1403
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:17494
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5918
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:436
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:773
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10183
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:574
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:737
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:751
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:18764
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4901
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2799
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7828
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3165
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:17401
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:630
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14162
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:771
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:695
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1108
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11566
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1316
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:656
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:666
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11806
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:436
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1517
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:200
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8850
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:522
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1805
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9032
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:93
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:725
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13869
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:20236
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:612
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1373
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4435
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:817
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4632
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7691
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2002
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1057
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6493
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7486
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1405
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:213
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:668
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:781
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:711
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4657
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:791
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1658
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1064
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11598
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8250
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1329
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9640
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1038
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11243
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1812
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:105
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1519
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16330
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7674
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:821
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1521
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:617
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6510
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3663
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:585
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:757
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11169
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16746
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:682
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:626
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:689
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:825
RouteCall
@ RouteCall
Definition: TrackUnit.h:1322
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11740
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:91
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:672
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:19807
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:744
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11198
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10459
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:677
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:203
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6411
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15303
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:749
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11752
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1378
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1652
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1577
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:574
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10450
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1316
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17159
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:99
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11764
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4569
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11687
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852